【问题标题】:Returning NULLs for data which does not exist for certain dates [duplicate]为某些日期不存在的数据返回 NULL [重复]
【发布时间】:2021-09-14 01:32:15
【问题描述】:

我有一个类似下面的数据表:

EntityId Date Value
1 5/30/2021 42
1 6/30/2021 35
1 7/31/2021 59
1 8/31/2021 61
2 7/31/2021 98
2 8/31/2021 100
3 8/31/2021 34

我想为每个唯一的 entityId 返回日历月结束日期 2021 年 5 月 31 日和 2021 年 8 月 31 日之间“值”列中的所有值。但是,每个唯一的 entityId 并不总是有所有此类日期的行,如果日期不存在,我想在 Value 列中返回 null 。在表上使用查询应该会产生以下数据:

EntityId Date Value
1 5/31/2021 42
1 6/30/2021 35
1 7/31/2021 59
1 8/31/2021 59
2 5/31/2021 NULL
2 6/30/2021 NULL
2 7/31/2021 98
2 8/31/2021 100
3 5/31/2021 NULL
3 6/30/2021 NULL
3 7/31/2021 NULL
3 8/31/2021 34

最简单的方法是什么?

【问题讨论】:

  • 日历或计数表...这个问题每天被问多次。
  • 顺便说一句,我注意到您没有接受对您之前的任何问题的单一答案 - 这有什么原因吗?如果您不接受答案,人们将不太愿意回答您的问题。
  • 道歉戴尔,我不是故意侮辱你。我会接受你的回答并从中吸取教训。
  • 你没有侮辱我。我只是指出网站规则,以便您获得最佳体验。但请务必重新查看您之前的所有问题,如果有合适的答案,请接受。 (我不相信我自己已经回答了你的任何问题)。如果提供的答案不能回答您的问题,您应该对此发表评论。

标签: sql sql-server tsql


【解决方案1】:

您需要从日期和实体列表开始。让我假设他们都在桌子上。所以,想法是使用cross join 来生成结果集中的行。然后用left join把剩下的数据带进来:

select e.entityid, d.date, t.value
from (select distinct entityid from data) e cross join
     (select distinct date from data) d left join
     data t
     on t.entityid = e.entityid and t.date = d.date;

注意:这使用子查询来生成日期和实体。如果此信息在其他表中,您可以直接使用这些表。

【讨论】:

    【解决方案2】:

    要创建完整范围的 EntityId 和 Date,查询使用不同值的 CROSS JOIN 作为“range_cte”。然后原始数据“data_cte”与“range_cte”完全外联。像这样的

    declare
      @start_dt           date='20210531',
      @end_dt             date='20210831';
    
    ;with
    data_cte(EntityId, [Date], [Value]) as (
        select *
        from (values (1, cast('20210531' as date), 42),
                     (1, cast('20210630' as date), 35),
                     (1, cast('20210731' as date), 59),
                     (1, cast('20210831' as date), 59),
                     (2, cast('20210731' as date), 98),
                     (2, cast('20210831' as date), 100),
                     (3, cast('20210831' as date), 34)) 
                     v(EntityId, [Date], [Value])),
    unq_id_cte(EntityId) as (
        select distinct EntityId
        from data_cte),
    nums_cte(n) as (
        select * 
        from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) v(n)),
    range_cte as (
        select top(datediff(month, @start_dt, @end_dt)+1) 
               eomonth(@start_dt, row_number() over (order by (select null))-1) mo_dt
        from nums_cte n1
             cross join nums_cte n2)
    select ui.EntityId, coalesce(r.mo_dt, d.[Date]) [Date], d.[Value] 
    from
      unq_id_cte ui
      cross join range_cte r
      full join data_cte d on ui.EntityId=d.EntityId
                              and r.mo_dt=d.[Date]
    order by ui.EntityId, r.mo_dt;
    
    EntityId    Date        Value
    1           2021-05-31  42
    1           2021-06-30  35
    1           2021-07-31  59
    1           2021-08-31  59
    2           2021-05-31  NULL
    2           2021-06-30  NULL
    2           2021-07-31  98
    2           2021-08-31  100
    3           2021-05-31  NULL
    3           2021-06-30  NULL
    3           2021-07-31  NULL
    3           2021-08-31  34
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多