问题
I have the following table:
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
I want to build a select query in PL/SQL to select the records with the most recent location_id per person_id. For the above sample, the desired result should be:
LOCATION_ID, PERSON_ID, DATE
5, 65, 2016-07-14
7, 23, 2016-10-28
(DATE expressed as 'YYYY-MM-DD')
Thank you!
回答1:
The other proposals are correct but the most compact and fastest solution is most likely when you use 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;
Other people prefer
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;
which does the same, but I am not so familiar with this clause. See aggregate_function KEEP
回答2:
You can first extract the most recent event for each person by grouping results by PERSON_ID
and selecting the MAX(DATE)
.
Then join the table with itself on those two columns to retrieve the 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
By the way, you should not use reserved words like DATE
for column names.
Here is fiddle to show it working: http://sqlfiddle.com/#!9/efdcb/2
回答3:
@quasoft is correct. Another way to deal with these kinds of GROUP BY
problems (when you want to return more column than what you want to group by. In your case, you need to return location_id, person_id. But you only need to group by person_id), is to use 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;
The query ordered
sort your rows for each group by date. The main query, returns the first 1 of each group after it is sorted. Hence, it will return the in this case the last one (we ordered by date_ desc).
回答4:
This might work!
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
来源:https://stackoverflow.com/questions/40435326/select-the-most-recent-entry