SQL 提问:如何return 只显示第一个和最后一个实例?
SQL Query: how to return only the first and last instance?
我有一个 table 显示同时执行多个作业的每个案例的状态,我希望显示结果以便它只显示第一个和最后一个实例。 (主要是我想知道这项工作是什么时候开始的,它的最后已知状态是什么)。
我已经通过 UNION 函数连接的 2 个相似的最小值、最大值和分组查询获得了结果。但是有没有更简单的方法呢?
但是,是否可以将 2 个实例显示在一行而不是分开的 2 行?因为第一个实例的日期将是开始日期,最后一个实例将是结束日期,而且我真的不关心第一个状态,因为它总是待定,我只想知道最后一个已知状态是什么
第一个 table 显示未过滤的结果,第二个 table 是所需的结果(但如果我们可以将第一个和最后一个实例组合在一行中,那就更好了)
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
非常感谢您
试试这个:
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
您需要将 < JOBS_TABLE > 替换为您的 table 名称。理想情况下,这应该将每组不同的 ID 和 JOB 值的第一行和最后一行的数据组合起来。如果作业未完成,则不会显示 END_DATE.
一种方法是按升序和降序使用 ROW_NUMBER
函数两次,以获取每组的第一行和最后一行。参见 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
此变体将扫描整个 table,计算行号并丢弃那些不满足过滤器的行。
第二种变体是使用 CROSS APPLY
,这可能更有效,如果 (a) 您的主要 table 有数百万行,(b) 您有一个小的 table 与所有 ID
和 Job
的列表,(c) 主要 table 具有适当的索引。在这种情况下,您可以为每个 (ID, Job)
执行索引查找,而不是读取主 table 的所有行(两次查找,一个用于第一行,一个用于最后一行)。
我不认为你的 UNION 想法有什么问题。这是你拥有的吗?
select id, job, status, max(date), job, note, 'max' 作为来自 test1 group by job UNION 的类型
select id, job, status, min(date), job, note, 'min' as type from test1 group by job;
我有一个 table 显示同时执行多个作业的每个案例的状态,我希望显示结果以便它只显示第一个和最后一个实例。 (主要是我想知道这项工作是什么时候开始的,它的最后已知状态是什么)。
我已经通过 UNION 函数连接的 2 个相似的最小值、最大值和分组查询获得了结果。但是有没有更简单的方法呢?
但是,是否可以将 2 个实例显示在一行而不是分开的 2 行?因为第一个实例的日期将是开始日期,最后一个实例将是结束日期,而且我真的不关心第一个状态,因为它总是待定,我只想知道最后一个已知状态是什么
第一个 table 显示未过滤的结果,第二个 table 是所需的结果(但如果我们可以将第一个和最后一个实例组合在一行中,那就更好了)
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
非常感谢您
试试这个:
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
您需要将 < JOBS_TABLE > 替换为您的 table 名称。理想情况下,这应该将每组不同的 ID 和 JOB 值的第一行和最后一行的数据组合起来。如果作业未完成,则不会显示 END_DATE.
一种方法是按升序和降序使用 ROW_NUMBER
函数两次,以获取每组的第一行和最后一行。参见 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
此变体将扫描整个 table,计算行号并丢弃那些不满足过滤器的行。
第二种变体是使用 CROSS APPLY
,这可能更有效,如果 (a) 您的主要 table 有数百万行,(b) 您有一个小的 table 与所有 ID
和 Job
的列表,(c) 主要 table 具有适当的索引。在这种情况下,您可以为每个 (ID, Job)
执行索引查找,而不是读取主 table 的所有行(两次查找,一个用于第一行,一个用于最后一行)。
我不认为你的 UNION 想法有什么问题。这是你拥有的吗?
select id, job, status, max(date), job, note, 'max' 作为来自 test1 group by job UNION 的类型 select id, job, status, min(date), job, note, 'min' as type from test1 group by job;