HAVING 子句仅在聚合分组不包含空值时过滤掉空行

HAVING clause to filter out null rows ONY if aggregate grouping contains not null values

我正在尝试从具有架构

的table创建汇总报告

PersonName varchar, IDNum int, CreateDate date

PersonName和CreateDate不为null,但是IDNum是可以为null的,这个table没有唯一约束,所以同一个PersonName可以有多个`IDNums,甚至多个null IDNums。

我想做的是创建一个按 CreateDate 分组的报告,如果该日期存在任何非空值,则忽略空 IDNums

因此,如果在 2 月 1 日存在 IDNum 为 20、21、23、NULL、NULL 的人,则报告在同一日期汇总 20、21、23 并忽略空值,如果另一个人在 2 月 1 日只存在 NULL IDNum,它们只显示一次 NULL。如果那个人在 2 月 2 日也作为 IDNums 25、30、NULL 存在,则他们在 2 月 1 日出现一次为 NULL,在 2 月 2 日再次出现为 25、30。 null 可以替换为其他一些默认值。不重要。

到目前为止我有

SELECT PersonName, COALESCE(IDNum, 0) IDNum, CreateDate FROM tbl GROUP BY PersonName, COALESCE(IDNum, 0), CreateDate HAVING COALESCE(IDNum, 0) >= CASE MAX(COALESCE(IDNum, 0)) WHEN 0 THEN 0 ELSE 1 END

这里的想法是,如果 IDNum 的计算结果为 0,如果另一个 IDNum 的计算结果大于 0,则不要在分组中对其进行计算,但这似乎不起作用。结果是相同的,就好像 having 子句不存在一样,我可以直观地看到同一 PersonName 的几个结果,其中包含同一日期的 0 和非零 IDNums。

检查此查询。只需删除重复的空值。然后数IDNum。取决于显示你想要的结果

declare @t table (
    PersonName varchar(10)
    , IDNum int
    , CreateDate date
)

insert into @t
values
    ('A', 20, '20180216')
    ,('A', 21, '20180216')
    ,('A', null, '20180216')
    ,('A', null, '20180216')
    ,('B', null, '20180216')
    ,('C', null, '20180216')
    ,('C', null, '20180216')

select
    PersonName, IDNum, CreateDate
from (
    select
        *, cnt = count(*) over (partition by PersonName, CreateDate) 
    from
        @t
    group by PersonName, IDNum, CreateDate
) t
where
    cnt = 1
    or (cnt > 1 and IDNum is not null)

输出

PersonName, IDNum, CreateDate
-----------------------------
A           20     2018-02-16
A           21     2018-02-16
B           NULL   2018-02-16
C           NULL   2018-02-16