简体   繁体   中英

SQL Query: how to return only the first and last instance?

I have a table that shows the status of each case with multiple jobs being performed simultaneously, I would like to have the results displayed so that it only shows the first and last instance. (Mainly I want to know when the job was first started and what's its last known status).

I've managed to get the results with 2 similar min, max, and group by queries joined by an UNION function. But is there a simpler way?

However, would it be possible to display the 2 instances on one line instead of 2 separate lines? because the date from the first instance will be the start date and the last instance will be the end date, and i don't really care about the first status because it's always pending, i just want to know what's the last known status

1st table shows unfiltered results and 2nd table is desired results (but if we can combine the first and last instance on one line that'd be even better)

ID  Status      Date       Job  Note
1   pending     1-Jul       A   abc
1   pending     2-Jul       A   xyz
1   pending     2-Jul       A   abc
1   done        3-Jul       B   xyz
1   done        4-Jul       A   abc
2   pending     1-Jul       A   abc
2   done        2-Jul       A   xyz
2   done        2-Jul       A   abc
2   pending     3-Jul       C   xyz
2   pending     4-Jul       C   xyz
2   pending     5-Jul       C   xyz
2   pending     6-Jul       C   xyz
3   pending     2-Jul       D   xyz
3   done        3-Jul       D   abc
3   pending     4-Jul       D   abc
3   pending     1-Jul       E   xyz
3   done        3-Jul       E   xyz

ID  Status      Date       Job  Note
1   pending     1-Jul       A   abc
1   done        3-Jul       B   xyz
1   done        4-Jul       A   abc
2   pending     1-Jul       A   abc
2   done        2-Jul       A   abc
2   pending     3-Jul       C   xyz
2   pending     6-Jul       C   xyz
3   pending     2-Jul       D   xyz
3   pending     4-Jul       D   abc
3   pending     1-Jul       E   xyz
3   done        3-Jul       E   xyz

Thank you very much in advance

One way to do it is to use ROW_NUMBER function twice in ascending and descending order to get first and last rows of each group. See SQL Fiddle

WITH
CTE
AS
(
  SELECT
    ID
    ,Status
    ,dt
    ,Job
    ,Note
    ,ROW_NUMBER() OVER (PARTITION BY ID, Job ORDER BY dt ASC) AS rnASC
    ,ROW_NUMBER() OVER (PARTITION BY ID, Job ORDER BY dt DESC) AS rnDESC
  FROM T
)
SELECT 
    ID
    ,Status
    ,dt
    ,Job
    ,Note
FROM CTE
WHERE rnAsc=1 OR rnDesc=1
ORDER BY ID, Job, dt

This variant would scan through the whole table, calculate row numbers and discard those rows that don't satisfy the filter.

The second variant is to use CROSS APPLY , which may be more efficient, if (a) your main table has millions of rows, (b) you have a small table with the list of all ID s and Job s, (c) the main table has appropriate index. In this case instead of reading all rows of the main table you can do index seek for each (ID, Job) (two seeks, one for first row plus one for the last row).

Try this:

SELECT A.ID, A.JOB, A.STATUS, B.START_DATE, CASE WHEN A.STATUS = 'done' THEN C.END_DATE ELSE NULL AS END_DATE
FROM <JOBS_TABLE> A
JOIN (SELECT ID, JOB, MIN(DATE) AS START_DATE FROM <JOBS_TABLE> GROUP BY ID, JOB) B
ON A.ID = B.ID
AND A.JOB = B.JOB
JOIN (SELECT ID, JOB, MAX(DATE) AS END_DATE FROM <JOBS_TABLE GROUP BY ID, JOB) C
ON A.ID= C.ID
AND A.JOB = C.JOB
AND A.DATE = C.END_DATE

You'll need to replace < JOBS_TABLE > with whatever your table name is. Ideally, this should combine the data from the first and last rows for each distinct set of ID and JOB values. If the job is not finished, it will not show an END_DATE.

I don't think there's much wrong with your UNION idea. Is this what you have?

select id, job, status, max(date), job, note, 'max' as type from test1 group by job UNION select id, job, status, min(date), job, note, 'min' as type from test1 group by job;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM