2016-04-27 7 views
0

Ich benutze SQL Server 2012. Ich habe eine Tabelle (LocationResults) mit mehreren Spalten. Ich möchte alle Spalten erhalten, die auch in einer anderen Tabelle vorhanden sind (TargetAssociationDetails) - aber nur die Zeilen, die zuletzt eingefügt wurden und auch in der zweiten Tabelle vorhanden sind.Wie bekomme ich den neuesten Datensatz basierend auf Timestamp in SQL Server mit Join

Meine TargetAssociationDetails Tabelle:

MSISDN  IMEI IMSI 
-------------------------- 
14085551107 NULL NULL 
14085551108 NULL NULL 
14085551113 NULL NULL 

Meine LocationResults Tabelle:

Latitude Longitude  MSISDN  IMSI IMEI RecordedTimeStamp 
--------------------------------------------------------------------------- 
57.785125 -123.40476  14085551107 NULL NULL 05:54.8 
57.78374111 -123.4027269 14085551107 NULL NULL 19:12.6 
57.78476194 -123.4045131 14085551107 NULL NULL 09:08.3 
57.61768861 -123.4081439 14085551108 NULL NULL 19:08.4 
57.801585 -123.45619  14085551114 NULL NULL 19:08.5 
57.55303194 -123.3019161 14085551113 NULL NULL 19:08.5 

Diese meine Frage ist -

SELECT MAX(lr.RecordTimestamp) AS RecordedTimeStamp, lr.IMEI, lr.IMSI, lr.MSISDN 
FROM LocationResults lr LEFT OUTER JOIN TargetAssosiationDetails tad ON 
tad.IMEI = lr.IMEI AND tad.IMSI = lr.IMSI AND tad.MSISDN = lr.MSISDN 
GROUP BY lr.IMEI, lr.IMSI,lr.MSISDN 

Aber in diesem Fall, ich bin zu bekommen nicht in der Lage alle Spalten. Ich kann nur die Spalten abrufen, nach denen ich gruppiere.

Das Ergebnis was ich will -

Latitude Longitude  MSISDN  IMSI IMEI RecordedTimeStamp 
--------------------------------------------------------------------------- 
57.78374111 -123.4027269 14085551107 NULL NULL 19:12.6 
57.61768861 -123.4081439 14085551108 NULL NULL 19:08.4 
57.55303194 -123.3019161 14085551113 NULL NULL 19:08.5 

Ich bin absolut neu anfragende DB so wird es groß sein, wenn Sie ein Skript zusammen mit einer Erklärung von veröffentlichen können, was es tut.

Vielen Dank im Voraus.

+0

Sie möchten den letzten Zeitstempel in Bezug auf welche anderen Spalten? –

+0

es ist immer Goo, die Version Ihres SQL-Servers zu markieren – FLICKER

Antwort

2

Solange Sie MS SQL Server 2008 verwenden oder höher Sie die Fensterfunktion ROW_NUMBER() diese Ergebnisse zu erzielen verwenden können. Die Funktion ROW_NUMBER() ermöglicht es Ihnen, jede Zeile nach einer bestimmten Reihenfolge zu nummerieren (in diesem Fall den Zeitstempel absteigend) und diese Reihenfolge basierend auf einem Wert (in diesem Fall MSISDN) neu zu starten: Also für jeden einzelnen Wert der MSISDN-Nummer die Zeilen in der Reihenfolge vom höchsten Timestamp bis zum geringsten. Führen Sie dann eine innere Verknüpfung zu dieser Abfrage aus Ihrer LocationResults-Tabelle ONLY, wo die Zeilennummer 1 ist, da dies bedeutet, dass es die neueste Zeile ist.

Da es scheint, dass jede Zeile durch drei Felder statt einer identifiziert wird, müssen Sie Ihre Zeile durch diese drei Felder partitionieren sowie sie in der Verknüpfung verwenden. Dies geschieht einfach, indem Sie sie in der Klausel PARTITION BY getrennt durch Kommas auflisten.

SELECT * 
FROM LocationResults AS lr 
INNER JOIN (
    SELECT *, 
     -- number the rows based on the time stamp descending and restart the ordering for each MSISDN value 
     ROW_NUMBER() OVER (PARTITION BY MSISDN, IMEI, IMSI ORDER BY RecordedTimeStamp DESC) AS rnum 
    FROM TargetAssociationDetails 
) AS d ON d.MSISDN=lr.MSISDN 
    AND d.IMEI=lr.IMEI 
    AND d.IMSI=lr.IMSI 
    -- join on row number 1 because that will be the newest row 
    AND d.rnum=1 
+0

Ich habe die Frage aktualisiert, um eine Beziehung zu zeigen, die mit einer anderen Tabelle existiert, und ich brauche auch die Bedingung für 3 Felder angewendet werden - MSISDN, IMEI und IMSI. – yazz

+0

Aktualisieren Sie anschließend die Join-Bedingung mit den zusätzlichen Feldern. Mein Code ist nur ein Beispiel für die Verwendung der Funktion 'ROW_NUMBER()', um den neuesten Datensatz aus einer Tabelle abzurufen. Wenn Sie nicht wissen, wie man das macht, könnten Sie eine andere Frage stellen, aber ich würde empfehlen, zu lesen, wie Tabellen-Joins in SQL zuerst funktionieren, da Ihre neue Frage wahrscheinlich als Duplikat geschlossen wird. –

+0

@yazz Nach ein wenig Überlegung habe ich festgestellt, dass Sie auch die PARTITION BY-Klausel und die JOIN-Bedingung aktualisieren müssen, wenn Ihre Zeilen durch mehrere Felder eindeutig sind. Ich habe meine Antwort aktualisiert, um das zu reflektieren. Obwohl Ihre Beispieldaten nur NULL in diesen Spalten anzeigen, bedeutet dies, dass Ihre Joins nicht funktionieren (weil NULL! = NULL). Wenn dies der Fall ist, müssen Sie diese NULL-Werte in Ihrer Join-Bedingung behandeln oder überdenken, wie Ihre Zeilen verbunden sind. –

1

versuchen, diese

;with cte as (
select Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp 
    , row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) as RN 
from LocationResults 
) 
select * 
from cte 
where RN = 1 
0

Es gibt viele Möglichkeiten it.Below zu tun, man Art und Weise, die erfordert nicht CTE oder abgeleitete Tabellen ..

select top 1 with ties Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp 
from 
LocationResults 
order by row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) 
+0

Ich bin immer noch nicht in der Lage, diese Abfrage anzuwenden, um eine Beziehung mit einer anderen Tabelle aufzunehmen. Ich habe die Frage aktualisiert. – yazz

0

Als Mike D. erwähnt dort sind viele Möglichkeiten, TU es. Hier ist mein Ansatz:

DECLARE 
    @TargetAssociationDetails TABLE (
             MSISDN BIGINT, 
             IMEI VARCHAR(100), 
             IMSI VARCHAR(100) 
            ) 

DECLARE 
    @LocationResults TABLE (
            Latitude   FLOAT, 
            Longitude   FLOAT, 
            MSISDN    BIGINT, 
            IMSI    VARCHAR(100), 
            IMEI    VARCHAR(100), 
            RecordedTimeStamp DATETIME 
           ) 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.785125, -123.40476, 14085551107, NULL, NULL, '05:54.8') 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.78374111, -123.4027269, 14085551107, NULL, NULL, '19:12.6') 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.78476194, -123.4045131, 14085551107, NULL, NULL, '09:08.3') 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.61768861, -123.4081439, 14085551108, NULL, NULL, '19:08.4') 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.801585, -123.45619, 14085551114, NULL, NULL, '19:08.5') 

INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp) 
VALUES (57.55303194, -123.3019161, 14085551113, NULL, NULL, '19:08.5') 

INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI) 
VALUES (14085551107, NULL, NULL) 

INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI) 
VALUES (14085551108, NULL, NULL) 

INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI) 
VALUES (14085551113, NULL, NULL) 

SELECT 
    LR.Latitude, 
    LR.Longitude, 
    TAD.MSISDN, 
    TAD.IMSI, 
    TAD.IMEI, 
    LR.RecordedTimeStamp 
FROM @TargetAssociationDetails TAD 
    INNER JOIN (
        SELECT 
         MAX(LR.RecordedTimeStamp) AS RecordedTimeStamp, 
         LR.MSISDN 
        FROM @LocationResults LR 
        GROUP BY 
         LR.MSISDN 
       ) _LR ON _LR.MSISDN = TAD.MSISDN 
    INNER JOIN @LocationResults LR ON [_LR].MSISDN = LR.MSISDN AND [_LR].RecordedTimeStamp = LR.RecordedTimeStamp 

Aber ich muss fair sein, ich hätte Mikes Weg verwendet. Es ist eine Verbindung weniger und ein gutes Beispiel.

0

Wenn verfügbar, verwenden Sie, wie es hier ist, ROW_NUMBER() OVER(), um nur die Zeilen zu finden, die Sie benötigen.

Dann können Sie mit den zugehörigen Tabelle (n) verbinden.Hier ist ein Beispiel einer „abgeleitete Tabelle“ mit:

SELECT * 
FROM (
     SELECT *, 
     row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) as rowno 
    FROM LocationResults 
    ) as lr 
LEFT OUTER JOIN TargetAssosiationDetails tad ON tad.IMEI = lr.IMEI AND tad.IMSI = lr.IMSI AND tad.MSISDN = lr.MSISD 
WHERE lr.rowno = 1 

Andere haben einen „gemeinsamen Tabellenausdruck“ vorgeschlagen (CTE - diese benötigen mit WITH ... AS), aber es gibt keinen Vorteil darin, dass Ansatz. Persönlich glaube ich, dass es für relative Anfänger wichtig ist, SQL zu verstehen und mit abgeleiteten Tabellen vertraut zu sein, bevor CTEs wahllos verwendet werden.

Verwandte Themen