2016-11-05 3 views
1

ich die folgende Tabelle haben:den neuesten Eintrag wählen

LOCATION_ID, PERSON_ID, DATE 
3, 65, 2016-06-03 
7, 23, 2016-10-28 
3, 23, 2016-08-05 
5, 65, 2016-07-14 

ich eine Auswahlabfrage in PL/SQL aufbauen wollen die Datensätze mit dem letzten location_id pro person_id auszuwählen. Für das obige Beispiel sollte das gewünschte Ergebnis sein:

LOCATION_ID, PERSON_ID, DATE 
5, 65, 2016-07-14 
7, 23, 2016-10-28 

(DATUM ausgedrückt als 'YYYY-MM-DD')

Thank you!

+0

Haben Sie alle Antworten überprüft, die Sie erhalten haben? Sie haben den ineffizientesten als "korrekt" markiert. Wernfrieds * zweite * Lösung ist eindeutig die beste. Es macht nur einen Durchlauf über die gesamte Tabelle - es gibt keine Joins, also wird es VIEL schneller als jede Join-basierte Lösung sein. Die zweitbeste Lösung (zwei Durchgänge, aber immer noch keine Verbindungen, also immer noch viel schneller) sind Hawks Lösung und Wernfrieds * erste * Lösung. Wenn Sie ihre Lösungen nicht verstanden haben, könnten Sie ** fragen **. – mathguy

+0

Ich markierte "richtig" die erste Antwort, die ich las und für mich arbeitete. Heute lese ich alle Antworten. –

Antwort

4

Die anderen Vorschläge sind korrekt, aber die kompakteste und schnellste Lösung ist sehr wahrscheinlich, wenn Sie FIRST_VALUE and LAST_VALUE Analytic Functions

SELECT DISTINCT 
    FIRST_VALUE(LOCATION_ID) OVER (PARTITION BY PERSON_ID ORDER BY THE_DATE 
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS LOCATION_ID, 
    PERSON_ID, 
    MAX(THE_DATE) OVER (PARTITION BY PERSON_ID) AS LAST_DATE 
FROM YOUR_TABLE; 

Andere Leute

bevorzugen verwenden
SELECT 
    MAX(LOCATION_ID) KEEP (DENSE_RANK FIRST ORDER BY DATE) as LOCATION, 
    PERSON_ID, 
    MAX(DATE) as LAST_DATE 
FROM YOUR_TABLE 
GROUP BY PERSON_ID; 

die das gleiche tut, aber ich bin nicht so vertraut mit dieser Klausel. Siehe aggregate_function KEEP

+0

Die Präferenz für die zweite Lösung ist gerechtfertigt, da sie die richtige ist. Es macht nicht dasselbe wie das erste. Die erste Lösung verwendet analytische Funktionen, so dass das Ergebnis so viele Zeilen enthält wie die Basistabelle (mit vielen Duplikaten).Sie müssen erneut auswählen (oder "gruppieren nach" oder etwas tun), um die Duplikate zu entfernen. – mathguy

+0

@mathguy, habe ich DISTINCT in der ersten Abfrage verwendet. Sollte stimmen. –

+0

Oh, Entschuldigung, ich habe nicht aufgepasst. Es ist "korrekt" in dem Sinne, dass es die richtige Antwort geben wird, aber es kann sehr ineffizient sein, wenn die Tabelle groß ist. Wenn Sie "distinct" verwenden müssen (entweder explizit oder versteckt in einer GROUP BY usw.), ist dies ein Zeichen dafür, dass eine bessere Lösung vorhanden sein kann. In diesem Fall - es ist Ihre zweite Lösung. – mathguy

1

Sie können zuerst das neueste Ereignis für jede Person extrahieren, indem Sie die Ergebnisse nach PERSON_ID gruppieren und MAX(DATE) auswählen.

kommen dann die Tabelle mit sich selbst auf diesen beiden Säulen der LOCATION_ID

SELECT 
    YOUR_TABLE.LOCATION_ID, 
    YOUR_TABLE.PERSON_ID, 
    YOUR_TABLE.DATE 
FROM 
    (SELECT 
    PERSON_ID, MAX(DATE) AS max_date 
    FROM 
    YOUR_TABLE 
    GROUP BY 
    PERSON_ID 
) AS t1 
LEFT JOIN 
    YOUR_TABLE 
ON 
    YOUR_TABLE.PERSON_ID = t1.PERSON_ID 
    AND 
    YOUR_TABLE.DATE = t1.max_date 

Durch die Art und Weise abzurufen, sollten Sie nicht reservierten Wörter wie DATE für Spaltennamen verwenden.

Hier Geige zu zeigen, es funktioniert: http://sqlfiddle.com/#!9/efdcb/2

+0

DATUM Name war nur für die Präsentation meines Problems. Danke, dass Sie darauf hingewiesen haben –

0

@quasoft ist richtig. Eine andere Möglichkeit, mit dieser Art von GROUP BY Probleme umzugehen (wenn Sie mehr Spalte zurückgeben wollen als was Sie gruppieren möchten. In Ihrem Fall müssen Sie location_id, person_id zurückgeben. Aber Sie müssen nur nach person_id gruppieren) Verwenden Sie analytical functions.

--schema: 
CREATE TABLE my_table 
    ( 
    location_id NUMBER, 
    person_id NUMBER, 
    date_  DATE 
); 

INSERT ALL 
INTO my_table 
VALUES (3, 65, To_date('2016-06-03', 'YYYY-MM-DD')) 
INTO my_table 
VALUES (7, 23, To_date('2016-10-28', 'YYYY-MM-DD')) 
INTO my_table 
VALUES (3, 23, To_date('2016-08-05', 'YYYY-MM-DD')) 
INTO my_table 
VALUES (5, 65, To_date('2016-07-14', 'YYYY-MM-DD')) 
SELECT * 
FROM dual; 

--query: 
WITH ordered 
    AS (SELECT location_id, 
       person_id, 
       date_, 
       Row_number() 
        over ( 
        PARTITION BY person_id 
        ORDER BY date_ DESC) RN 
     FROM my_table) 
SELECT location_id, 
     person_id, 
     date_ 
FROM ordered 
WHERE rn = 1; 

Die Abfrage ordered sortieren Sie Ihre nach dem Datum für jede Gruppe Reihen. Die Hauptabfrage gibt die erste 1 jeder Gruppe zurück, nachdem sie sortiert wurde. Daher wird es in diesem Fall das letzte zurückgeben (wir haben nach Datum_desk sortiert).

0

Dies könnte funktionieren!

SELECT * FROM Your_Table A 
JOIN (SELECT PERSON_ID,MAX(DATE) as MaxDate FROM Your_Table 
GROUP BY PERSON_ID) B 
ON A.PERSON_ID = B.PERSON_ID AND A.DATE = B.MaxDate 
Verwandte Themen