如何跨多列和多行“汇总”数据
Posted
技术标签:
【中文标题】如何跨多列和多行“汇总”数据【英文标题】:How to "Roll-Up" data across multiple columns and rows 【发布时间】:2020-09-08 12:43:05 【问题描述】:我有一个审核表,我们在其中记录对数据库中字段的更改。我有一个查询,我能够从审计中获取关于几列、它们记录的更改以及何时与适用的 ID 相关联的数据子集。以下是输出的示例:
ID ada IsHD HDF DTStamp
-----------------------------------------------------
68 NULL 0 0 2020-04-28 21:12:21.287
68 NULL NULL NULL 2020-04-17 14:59:49.700
68 No/Unsure NULL NULL 2020-04-17 14:03:46.160
68 NULL 0 0 2020-04-17 13:49:49.720
102 NULL NULL NULL 2020-04-30 13:11:15.273
102 No/Unsure NULL NULL 2020-04-20 16:00:35.410
102 NULL 1 1 2020-04-20 15:59:55.750
105 No/Unsure 1 1 2020-04-17 12:06:10.833
105 NULL NULL NULL 2020-04-13 07:51:30.180
126 NULL NULL NULL 2020-05-01 17:59:24.460
126 NULL 0 0 2020-04-28 21:12:21.287
我想弄清楚的是最有效的方法是“汇总”给定 ID 的多行,以便保留最新的非 NULL 值,只为该 ID 留下一行。
也就是转这个:
68 NULL 0 0 2020-04-28 21:12:21.287
68 NULL NULL NULL 2020-04-17 14:59:49.700
68 No/Unsure NULL NULL 2020-04-17 14:03:46.160
68 NULL 0 0 2020-04-17 13:49:49.720
102 NULL NULL NULL 2020-04-30 13:11:15.273
102 No/Unsure NULL NULL 2020-04-20 16:00:35.410
102 NULL 1 1 2020-04-20 15:59:55.750
进入这个:
68 No/Unsure 0 0 2020-04-28 21:12:21.287
102 No/Unsure 1 1 2020-04-30 13:11:15.273
...等等。这几乎就像你要按下结果的顶部并挤出所有的 NULL 一样。
将上述结果转储到临时表@audit
然后我运行以下查询:
SELECT DISTINCT a.[ID]
, (SELECT TOP 1 [ADA]
FROM @audit
WHERE [ID] = a.[ID]
AND [ADA] IS NOT NULL
ORDER BY [DTStamp] DESC) AS 'ADA'
, (SELECT TOP 1 [IsHD]
FROM @audit
WHERE [ID] = a.[ID]
AND [IsHD] IS NOT NULL
ORDER BY [DTStamp] DESC) AS 'IsHD'
, (SELECT TOP 1 [HDF]
FROM @audit
WHERE [ID] = a.[ID]
AND [HDF] IS NOT NULL
ORDER BY [DTStamp] DESC) AS 'HDF'
, (SELECT Max([DTStamp])
FROM @audit
WHERE [ID] = a.[ID]) AS 'DTStamp'
FROM @audit a
ORDER BY [ID]
这是我想出的方法,它确实有效,但感觉非常笨拙且效率低下。有没有更好的方法来实现最终目标?
【问题讨论】:
【参考方案1】:如果您希望每个 id 一行,则使用聚合:
select id, max(ada), max(IsHD), max(HDF), max(DTStamp)
from @audit a
group by id;
这适用于您提供的数据,并且似乎符合您想要的规则。
【讨论】:
非常感谢,这很好用。我曾想过这个问题,但我不相信自己会这么简单。去搞清楚。 :) 在将您的示例付诸实施后,我发现这种逻辑不成立的情况,因为我认为我首先有疑问。我提到我需要“最新的非 NULL 值”,但是您给出的示例获取了最大值,对于字符串来说,最大值是字母表中较高的值,INT 成为最大的数字......我需要 newest i> 或 最近的 不只是 Max。我更新了我的查询以更清楚地说明这一需求。【参考方案2】:我了解您希望每列的每个 id
的“最新”非空值,使用列 DTStamp
进行排序。
您使用多个子查询的方法可以满足您的需求。另一种方法是使用多个row_number()
s 和条件聚合。这可能实际上更有效,因为它避免了对表的多次扫描。
select
id,
max(case when rn_ada = 1 then ada end) ada,
max(case when rn_isHd = 1 then isHd end) isHd,
max(case when rn_hdf = 1 then hdf end) hdf,
max(DTStamp) DTStamp
from (
select
a.*,
row_number() over(
partition by id
order by case when ada is not null then DTStamp end desc
) rn_ada,
row_number() over(
partition by id
order by case when isHd is not null then DTStamp end desc
) rn_isHd,
row_number() over(
partition by id
order by case when hdf is not null then DTStamp end desc
) rn_hdf
from @audit a
) t
group by id
order by id
Demo on DB Fiddle:
编号 |阿达 |是高清 |高清晰度电视 | DTStamp --: | :-------- | ---: | --: | :------------------------ 68 |否/不确定 | 0 | 0 | 2020-04-28 21:12:21.287 102 |否/不确定 | 1 | 1 | 2020-04-30 13:11:15.273【讨论】:
以上是关于如何跨多列和多行“汇总”数据的主要内容,如果未能解决你的问题,请参考以下文章
Angular项目间的模板共享:如何跨多项目重用公共HTML