sql—如何跨多个列和行“汇总”数据

6qftjkof  于 2021-08-13  发布在  Java
关注(0)|答案(2)|浏览(489)

我有一个审计表,我们在其中记录对数据库中字段的更改。我有一个查询,在那里我能够从审计中获得关于几个列的数据子集,它们记录的更改,以及何时与适用的id相关联。下面是输出的示例:

  1. ID ada IsHD HDF DTStamp
  2. -----------------------------------------------------
  3. 68 NULL 0 0 2020-04-28 21:12:21.287
  4. 68 NULL NULL NULL 2020-04-17 14:59:49.700
  5. 68 No/Unsure NULL NULL 2020-04-17 14:03:46.160
  6. 68 NULL 0 0 2020-04-17 13:49:49.720
  7. 102 NULL NULL NULL 2020-04-30 13:11:15.273
  8. 102 No/Unsure NULL NULL 2020-04-20 16:00:35.410
  9. 102 NULL 1 1 2020-04-20 15:59:55.750
  10. 105 No/Unsure 1 1 2020-04-17 12:06:10.833
  11. 105 NULL NULL NULL 2020-04-13 07:51:30.180
  12. 126 NULL NULL NULL 2020-05-01 17:59:24.460
  13. 126 NULL 0 0 2020-04-28 21:12:21.287

我想弄清楚的是,最有效的方法是“汇总”给定id的多行,以便保留最新的非空值,只为该id保留一行。
也就是说,转动这个:

  1. 68 NULL 0 0 2020-04-28 21:12:21.287
  2. 68 NULL NULL NULL 2020-04-17 14:59:49.700
  3. 68 No/Unsure NULL NULL 2020-04-17 14:03:46.160
  4. 68 NULL 0 0 2020-04-17 13:49:49.720
  5. 102 NULL NULL NULL 2020-04-30 13:11:15.273
  6. 102 No/Unsure NULL NULL 2020-04-20 16:00:35.410
  7. 102 NULL 1 1 2020-04-20 15:59:55.750

对此:

  1. 68 No/Unsure 0 0 2020-04-28 21:12:21.287
  2. 102 No/Unsure 1 1 2020-04-30 13:11:15.273

……等等。就像你要把结果的顶端往下压,然后挤出所有的空值一样。
将上述结果转储到temp表中 @audit 然后运行以下查询:

  1. SELECT DISTINCT a.[ID]
  2. , (SELECT TOP 1 [ADA]
  3. FROM @audit
  4. WHERE [ID] = a.[ID]
  5. AND [ADA] IS NOT NULL
  6. ORDER BY [DTStamp] DESC) AS 'ADA'
  7. , (SELECT TOP 1 [IsHD]
  8. FROM @audit
  9. WHERE [ID] = a.[ID]
  10. AND [IsHD] IS NOT NULL
  11. ORDER BY [DTStamp] DESC) AS 'IsHD'
  12. , (SELECT TOP 1 [HDF]
  13. FROM @audit
  14. WHERE [ID] = a.[ID]
  15. AND [HDF] IS NOT NULL
  16. ORDER BY [DTStamp] DESC) AS 'HDF'
  17. , (SELECT Max([DTStamp])
  18. FROM @audit
  19. WHERE [ID] = a.[ID]) AS 'DTStamp'
  20. FROM @audit a
  21. ORDER BY [ID]

这就是我所想到的,它确实起作用,但感觉非常糟糕和低效。有没有更好的方法来实现最终目标?

hfyxw5xn

hfyxw5xn1#

如果希望每个id有一行,请使用聚合:

  1. select id, max(ada), max(IsHD), max(HDF), max(DTStamp)
  2. from @audit a
  3. group by id;

这适用于您提供的数据,并且似乎符合您想要的规则。

6fe3ivhb

6fe3ivhb2#

我知道您需要每个 id 对于每列,使用列 DTStamp 为了订购。
使用多个子查询的方法可以实现所需的功能。另一种方法是使用多个 row_number() 和条件聚合。这实际上可能更有效,因为它避免了对表的多次扫描。

  1. select
  2. id,
  3. max(case when rn_ada = 1 then ada end) ada,
  4. max(case when rn_isHd = 1 then isHd end) isHd,
  5. max(case when rn_hdf = 1 then hdf end) hdf,
  6. max(DTStamp) DTStamp
  7. from (
  8. select
  9. a.*,
  10. row_number() over(
  11. partition by id
  12. order by case when ada is not null then DTStamp end desc
  13. ) rn_ada,
  14. row_number() over(
  15. partition by id
  16. order by case when isHd is not null then DTStamp end desc
  17. ) rn_isHd,
  18. row_number() over(
  19. partition by id
  20. order by case when hdf is not null then DTStamp end desc
  21. ) rn_hdf
  22. from @audit a
  23. ) t
  24. group by id
  25. order by id

db小提琴演示:

  1. id | ada | isHd | hdf | DTStamp
  2. --: | :-------- | ---: | --: | :----------------------
  3. 68 | No/Unsure | 0 | 0 | 2020-04-28 21:12:21.287
  4. 102 | No/Unsure | 1 | 1 | 2020-04-30 13:11:15.273
展开查看全部

相关问题