2016-06-24 16 views
1

Freunde,So wählen Sie Datensätze aus SQL Server

Ich habe ein SQL-Problem, das ich Hilfe verwenden könnte. Ich arbeite mit SQL Server 2008.

Der Anwendungsfall ist der folgende. Wir haben ein System, in dem Nutzer Videos ansehen und jedes Mal, wenn ein Nutzer ein Video ansieht, erfassen wir diese Aktivität. Wir erfassen jedes Mal drei Eigenschaften. AssetID (ein Asset ist ein Video), customerid und Status.

Ein Datensatz kann drei verschiedene Status haben; "Vervollständigen", "Spielen" und "Starten".

Die Person, die diesen Teil des Systems geschrieben hat, ist kein Entwickler. Statt den Status eines vorhandenen Datensatzes zu aktualisieren, wird bei jeder Wiedergabe eines Videos ein neuer Duplikateintrag eingefügt. Daher haben wir Tausende von doppelten Datensätzen. Hier ist ein Beispieldatensatz

enter image description here

Das Problem, das ich lösen müssen, ist, einen Datensatz zu wählen, indem AssetID, customerid und Status. Ich muss einen Datensatz auswählen, der den Status "Fertigstellung" hat, wenn er existiert.

Wenn ein Datensatz den Status "Abspielen" hat, aber kein Datensatz mit derselben Assetid und customerid mit dem Status "Completion" vorhanden ist, wählen Sie diesen Datensatz aus.

Wenn ein Datensatz den Status 'start' hat, aber kein Datensatz mit derselben Assetid und customerid mit dem Status 'completion' oder 'playing' existiert, dann wählen Sie diesen Datensatz aus.

Hier ist Beispielcode, wo ich versucht habe, eine CASE-Anweisung zu verwenden, um das Problem zu lösen. Ich versuchte auch eine andere Fallanweisung mit einer NOT IN Unterabfrage, aber ohne Erfolg.

INSERT INTO #ViewTime (AssetID, CustomerID, ViewTime) 
SELECT 
    tt.customerid, tt.assetId, tt.assetstatus, 
    CASE WHEN 
     tt.AssetStatus = 'COMPLETION' 
    AND 
     ISNUMERIC(timeposition) = 1 
    THEN 
     CONVERT(Numeric(18,3), timePosition) 
    WHEN 
     tt.AssetStatus = 'PLAYING' 
    AND 
     ISNUMERIC(timeposition) = 1 
    THEN 
     CONVERT(Numeric(18,3), timePosition) 
    WHEN 
     tt.AssetStatus = 'START' 
    AND 
     ISNUMERIC(timeposition) = 1 
    THEN 
     CONVERT(Numeric(18,3), timePosition) 
    ELSE null 
    END AS ViewTime 
FROM 
    TableAssetTracking tt 
    inner join TableAssets ta 
    on tt.AssetID = ta.AssetID 
WHERE 
    tt.timePosition is not null 
AND 
    AssetBuffering is null 

Alle Vorschläge würden sehr geschätzt werden. Danke, Derek

+2

Anstatt ein Bild für Beispieldaten wie über einige ddl und Verbrauchsdaten? Auch eine Erklärung dessen, was Sie als Ausgabe erwarten, würde erheblich helfen. Sie könnten diesen Artikel in Betracht ziehen. http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ –

+0

Auch diese Frage könnte besser für dba.stackexchange.com – John

+0

geeignet sein @John Auf DBA würden sie nur diese Basis SQL betrachten und bleiben auf SE – Paparazzi

Antwort

1

Das Problem, das ich lösen muss, ist, einen Datensatz nach AssetID, CustomerID und Status auszuwählen.

Ich muss einen Datensatz auswählen, der den Status "Abschluss" hat, wenn es existiert.

select distinct assetID, CustomerID 
    from table 
where status = 'complete' 

Wenn ein Datensatz einen Status ‚spielen‘, aber keine Aufzeichnungen mit dem gleichen AssetID und customerid mit dem Status ‚Abschluss‘ vorhanden ist, wählen Sie dann diesen Datensatz.

select assetID, CustomerID 
    from table 
where status = 'playing' 
except 
select assetID, CustomerID 
    from table 
where status = 'complete' 

Wenn ein Datensatz einen Status von ‚Start‘, aber keine Aufzeichnungen mit dem gleichen AssetID und customerid mit dem Status entweder ‚Abschluss‘ oder ‚spielen‘ vorhanden ist, wählen Sie dann diesen Datensatz.

select assetID, CustomerID 
    from table 
where status = 'start' 
except 
select assetID, CustomerID 
    from table 
where status in ('complete', 'playing') 

Die oben ist nicht zu Ihnen geben Viewtime, dass ich in dem Beispiel sehen
Es Anweisung nicht in den Anforderungen war

select * 
from 
( select assetID, CustomerID, status, ViewTime 
     , row_number() over (partition by assetID, CustomerID order by status, ViewTime desc) as rn 
    from table 
    where status in ('complete', 'playing', 'start') 
) tt 
where tt.rn = 1 
+0

Down vote würden Sie gerne teilen, was es in dieser Antwort fehlt? – Paparazzi

1

Es gibt zahlreiche Möglichkeiten, dies zu tun. Hier ist eine.

Ich werde psuedocode verwenden, weil die Tabellen in Ihrem Beispielcode nicht mit der Beschreibung in Ihrer Frage übereinstimmen. Sie müssen diese Technik an Ihre Tabellen anpassen.

SELECT DISTINCT t.AssetId, t.CustomerId, (
    SELECT TOP 1 Status 
    FROM MyTable t1 
    WHERE t1.AssetId=t.AssetId 
    AND t1.CustomerId=t.CustomerId 
    ORDER BY CASE t1.Status 
    WHEN 'Completion' THEN 0 
    WHEN 'Playing' THEN 1 
    WHEN 'Started' THEN 2 
    ELSE 3 
    END ASC 
) AS Status 
FROM MyTable t 
+0

Ihr seid die Besten. Alle Lösungen waren großartig. Ich benutzte die von Paparazzi vorgeschlagene Lösung, und es löste mein Problem. Vielen Dank an alle. –

+0

Tab, würde es Ihnen etwas ausmachen, Ihre Lösung für mich zu klären? Ich möchte es vollständig verstehen. Ich bekomme den ORDER BY CASE. Der Teil, der mir unklar ist, ist die Unterabfrage mit der WHERE-Anweisung. Können Sie die Notwendigkeit für MyTable t1 und die WHERE-Anweisung von t1.AssetId = t.AssetId erklären? Vielen Dank. –

+0

Die WHERE-Anweisung wird benötigt, um die Unterabfrage mit der Hauptabfrage zu korrelieren, um sicherzustellen, dass Sie nur Status für die aktuelle Zeile der Hauptabfrage betrachten. –

1

Ich habe dies getan, um Ihnen eine breite Sicht auf Ihre Daten zu zeigen. Sie möchten den letzten Datensatz, der für jede Person und jedes Video in Ihre Tabelle eingefügt wurde, WIRKLICH identifizieren. So erhalten wir den letzten und erhalten dann den Status für diesen Datensatz.

IF OBJECT_ID('tempdb..#lastRecord') IS NOT NULL DROP TABLE #lastRecord 

    SELECT 
     max(trackingassetdatecreated) dt, 
     assetid, 
     customerid, 
    INTO #lastRecord 
    FROM 
     TableAssetTracking 
    GROUP BY 
     assetid, 
     customerid 

    SELECT 
     t.assetstatus, 
     lr.* 
    FROM 
     TableAssetTracking t 
    INNER JOIN 
     #lastRecord lr on 
      lr.trackingassetdatecreated = t.trackingassetdatecreated 
      and lr.assetid = t.assetid 
      and lr.customerid = t.customerid 
Verwandte Themen