【问题标题】:SQL query to return most recent data per group, then active/inactive per different groupSQL 查询以返回每个组的最新数据,然后每个不同组的活动/非活动
【发布时间】:2017-01-27 14:54:04
【问题描述】:

我有一个查询返回我想要的结果,但它运行了很长时间。有谁知道更好的写法吗?

我需要每组 Prgno/Prgdate 一行。 首先,我需要通过选择最近的记录来确定每个员工的状态。 然后,如果有任何员工活跃,则整个团队都活跃。

仅选择“A”记录是不够的,因为特定员工的非活动记录可能比活动记录更新。

这是查询:

SELECT X_Prgno,X_Prgdate,X_Status 
FROM (
    -- sq2 choose the 1st record when ordering by status, this will choose Active before Inactive
    SELECT X_Prgno,X_Prgdate,X_Status,
           ROW_NUMBER() OVER (PARTITION BY X_Prgno,X_Prgdate ORDER BY X_Status) AS rn
    FROM (
        -- sq1 choose the most recently updated record per empno, prgno, prgdate
        SELECT X_Empno,X_Prgno,X_Prgdate,X_Status,
               X_Upddate AS Updated_datetime,
               MAX(X_Upddate) OVER (PARTITION BY X_Empno,X_Prgno,X_Prgdate) AS Max_Updated_datetime
        FROM X_demo
        ) sq1
    WHERE Updated_datetime = Max_Updated_datetime) sq2
WHERE rn = 1

我首先选择了按 3 列(prgno、prgdate、员工)分组的最新记录。然后先选择活动记录,如果存在活动记录,仅按 2 列分组(prgno,prgdate)。

示例:(希望对您有所帮助,您可以在此示例集上运行上述查询)

create table X_demo(
X_Prgno char(6),
X_Prgdate char(8),
X_Empno int,
X_Status char(1),
X_Upddate datetime);
insert into X_demo values ('P43','20170124',1033,'A','2015-07-06 23:05:32.000');
insert into X_demo values ('P43','20170124',1033,'I','2015-07-06 23:05:07.000');
insert into X_demo values ('P43','20170124',1033,'I','2015-07-06 23:03:58.000');
insert into X_demo values ('P43','20170124',1034,'A','2015-06-03 09:29:46.000');
insert into X_demo values ('P43','20170124',1029,'I','2015-06-03 07:26:36.000');
insert into X_demo values ('P43','20170124',1033,'I','2015-06-02 14:52:53.000');
insert into X_demo values ('P43','20170124',1010,'I','2015-06-02 14:52:12.000');
insert into X_demo values ('P43','20170124',1029,'I','2015-08-29 13:27:35.000');
insert into X_demo values ('P43','20170124',1074,'I','2015-05-19 01:20:06.000');

如果我们按 Prgno、Prgdate 和 Empno 分组,我们应该返回 6 行,每个员工的最新数据。 然后通过 Prgno 和 Prgdate 重新组合以返回该组的“A”。

想要的结果:

X_Prgno X_Prgdate   X_Status
P43     20170124    A

感谢您的帮助。

如果我插入另外 2 条记录,两条 Active 员工记录的更多当前记录使它们处于非活动状态,则该组的结果应该是非活动的。

insert into X_demo values ('P43','20170124',1033,'I','2017-01-27 09:30:00.000');
insert into X_demo values ('P43','20170124',1034,'I','2017-01-27 09:30:00.000');

结果:

X_Prgno X_Prgdate   X_Status
P43     20170124    I

更新 - 2017-01-30

我将子查询的 MAX OVER PARTITION 部分更改为使用 ROW_NUMBER 函数。 它将查询运行时间缩短了几秒钟,但仍然运行时间过长。

SELECT X_Prgno,X_Prgdate,X_Status 
FROM (
    -- sq2 choose the 1st record when ordering by status, this will choose Active before Inactive
    SELECT X_Prgno,X_Prgdate,X_Status,
           ROW_NUMBER() OVER (PARTITION BY X_Prgno,X_Prgdate ORDER BY X_Status) AS sq2_rn
    FROM (
        -- sq1 choose the most recently updated record per prgno, prgdate, empno
        SELECT X_Prgno,X_Prgdate,X_Empno,X_Status,X_upddate,
               ROW_NUMBER() OVER (PARTITION BY X_Prgno,X_Prgdate,X_Empno
                        ORDER BY X_Upddate DESC,X_Status) AS sq1_rn
        FROM X_demo) sq1
    WHERE sq1_rn = 1) sq2
WHERE sq2_rn = 1

【问题讨论】:

  • 感谢您的帮助。
  • 那么您是否只需要每个组的最新活动记录(如果存在)?
  • 请发布您想要的结果。
  • 期望的结果是一行。我把它包括在上面了。

标签: sql sql-server


【解决方案1】:

您似乎希望在 date/prgno 上为员工创建一条记录,其中活动记录优先。

了解您想要做什么有助于简化查询。

SELECT x.*
FROM (SELECT x.*,
             ROW_NUMBER() OVER (PARTITION BY X_Prgno, X_PrgDate
                                ORDER BY X_Upddate DESC, status
                               ) as seqnum
      FROM X_demo x
     ) x
WHERE seqnum = 1;

对于此查询,(X_Prgno, X_PrgDate, status, X_Upddate) 上的索引将有助于提高性能。

【讨论】:

  • 差不多,但不完全。我需要按员工查找最近的员工,但如果有任何员工处于活动状态,那么该组就会处于活动状态。我正在寻找的结果是每个 Prgno/Prgdate 一行。
  • 我会看看我是否可以添加一个索引,它是一个应用程序数据库,我们通常不会碰这些。
  • @vkp 和 Gordon - 谢谢,但仍然不是解决方案。上面的查询返回一行,但并非在所有测试用例中都正确。如果所有员工的最近记录均处于非活动状态,则该组的结果应为“非活动”。如果任何员工的最新记录处于活动状态,则结果应为“活动”。在错误的情况下,员工 1033 和 1034 具有更新的非活动记录,没有其他员工处于活动状态,因此该组应该处于非活动状态。
  • @NancyF 。 . .我认为你只需要交换 ORDER BY 键(就像我刚才所做的那样)。
  • 我真的认为它需要是一个两部分的查询,因为内部查询包括员工,而外部查询没有。我只能查询每个员工最近的记录。然后,在获得最新记录的子集后,我可以检查它们中的任何一个是否处于活动状态。我无法按状态/日期排序,因为非活动记录可能比活动记录更新。我无法按日期/状态排序,因为不同员工的活动记录可能比非活动记录更新。
猜你喜欢
  • 2015-08-08
  • 1970-01-01
  • 2020-08-31
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多