【问题标题】:Merge multiple select statements and group them合并多个 select 语句并将它们分组
【发布时间】:2022-01-04 17:16:00
【问题描述】:

我很难找到有效的解决方案来解决我的问题。我认为这是一个相当普遍的问题,这就是我在这里提出问题的原因。

这就是问题所在。

假设我有多个选择,例如以下几个:

选择创建

date num_created
01-01-2021 10
01-02-2021 2
01-04-2021 13
SELECT Update
date num_update
01-01-2021 14
01-02-2021 2
01-03-2021 9
SELECT Delete
date num_delete
01-02-2021 2
01-05-2021 40

我想要这个最终输出

Final output
date num_created num_update num_deleted
01-01-2021 10 14 0
01-02-2021 2 2 2
01-03-2021 0 9 0
01-04-2021 13 0 0
01-05-2021 0 0 40

*我不能假设任何表格都有所有日期或匹配日期

【问题讨论】:

    标签: sql tsql merge


    【解决方案1】:

    您似乎想要按天分组计数:

    select
        tbls.date,
        sum(tbls.num_created) as num_created,
        sum(tbls.num_updated) as num_updated,
        sum(tbls.num_deleted) as num_deleted 
    from (
        select date, num_created, 0 as num_updated, 0 as num_deleted from tbl_create
        union all
        select date, 0 as num_created, num_updated, 0 as num_deleted from tbl_update
        union all
        select date, 0 as num_created, 0 as num_updated, num_deleted from tbl_delete) as tbls
    group by tbls.date
    

    请不要在不需要时滥用“with 语句”(如其他答案所示)。

    编辑 - 额外的简单查询:

        if object_id('tempdb..#tmp_dml_statement') is not null drop table #tmp_dml_statement 
        select date, num_created, 0 as num_updated, 0 as num_deleted
        into #tmp_dml_statement
        from tbl_create
        union all
        select date, 0 as num_created, num_updated, 0 as num_deleted
        from tbl_update
        union all
        select date, 0 as num_created, 0 as num_updated, num_deleted
        from tbl_delete
    

    【讨论】:

    • 这就是我最终做的,我觉得它不是特别干净,但它确实有效。请不要滥用 with 声明,是为了避免性能问题还是为了清洁?
    • 为了清洁。 With 应该用于递归查询或复杂的非递归查询以替换子查询或例如提高视图代码的可读性。在我的示例中,您可以看到派生查询(或者您可以使用 select into #tmp 语句来进一步简化 - 示例添加到答案中)。
    • 感谢您的解释!
    【解决方案2】:

    您可以在表和case语句之间执行完全外连接以选择如下日期(假设3个表/查询为a,b,c):

    With temp as
        (
        select case when a.date is not null then a.date else b.date end as date,num_created,num_update from a full join b on (a.date=b.date)
        ),
        temp1 as
        (
        select case when temp.date is not null then temp.date else c.date end as date,num_created,num_update,num_delete from temp full join c on (temp.date=c.date)
        )
        select * from temp1;
    

    【讨论】:

    • @waldo404 你能检查一下吗?
    • 是的,这行得通!我做了其他事情来解决我的问题,但我喜欢你解决问题的方式!谢谢
    【解决方案3】:

    假设表格是:

    tbl_create(dt, num_created) 
    tbl_update(dt, num_updated)
    tbl_delete(dt, num_deleted)
    

    从包含 3 个源表中所有日期的(临时)表开始:all_dates

    然后(左外)加入 3 个源表中的计数器。

    注意:'union' 删除重复项,无需担心(与 'union all' 相比)

    注意:coalesce(a,b) 返回第一个非空参数,所以你有零而不是 'null's

    with all_dates(dt) as (
       select dt from tbl_create
       union
       select dt from tbl_update
       union
       select dt from tbl_delete
    )
    select all_dates.dt
         , coalesce(tbl_create.num_created,0)    --   
         , coalesce(tbl_update.num_updated,0)
         , coalesce(tbl_delete.num_deleted,0)
    from all_dates 
      left outer join tbl_create on all_dates.dt = tbl_create.dt
      left outer join tbl_update on all_dates.dt = tbl_update.dt
      left outer join tbl_delete on all_dates.dt = tbl_delete.dt
    

    【讨论】:

    • 嗯,所以你首先得到一个日期列表,然后加入所有表,我想知道如果我有很多数据会发生什么,查询表两次?但仍然感谢您花时间回答我的问题!
    • 取决于您使用的数据库,但您会惊讶于查询优化器在优化查询方面的出色表现。
    • 好的,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 2018-02-16
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多