如何在 T-SQL 中处理具有“Union All”但让第二个“Select”始终出现在底部的查询?

Posted

技术标签:

【中文标题】如何在 T-SQL 中处理具有“Union All”但让第二个“Select”始终出现在底部的查询?【英文标题】:How do I Process a Query in T-SQL that has a "Union All" but get the Second "Select" to always appear at the bottom? 【发布时间】:2021-02-24 18:06:34 【问题描述】:

我有以下 SQL...

select Policy.[Effective Date], Policy.[Policy #], CLIENT.[NAME], Policy.[Premium]
From Policy, Client 
Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote' AND Client.[CLIENTID] = Policy.[CLIENTID] 

union all

select null, null, 'Totals', sum(Policy.[Premium])
From Policy, Client 
Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote' AND Client. 
CLIENTID = Policy.CLIENTID
Order By CLIENT.NAME

但结果看起来像......

【问题讨论】:

Bad Habits to Kick: Using old-style JOINs 【参考方案1】:

你需要添加一个额外的固定排序列。这通常非常有效,因为它通常使用Merge Concatenation、as explained by Paul White。

我建议您不要使用古老且已弃用的 , 加入语法。我还建议您不要使用需要引用的列名。

select Policy.[Effective Date], Policy.[Policy #], CLIENT.[NAME], Policy.[Premium], 1 AS ordering
From Policy
JOIN Client ON Client.[CLIENTID] = Policy.[CLIENTID] 
Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote'

union all

select null, null, 'Totals', sum(Policy.[Premium]), 2
From Policy
JOIN Client ON Client.CLIENTID = Policy.CLIENTID
Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote'
Order By Ordering, CLIENT.NAME

如果您不希望ordering 出现在结果中,那么您需要子查询:

select [Effective Date], [Policy #], [NAME], [Premium]
FROM (
    select Policy.[Effective Date], Policy.[Policy #], CLIENT.[NAME], Policy.[Premium], 1 AS ordering
    From Policy
    JOIN Client ON Client.[CLIENTID] = Policy.[CLIENTID] 
    Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote'

    union all

    select null, null, 'Totals', sum(Policy.[Premium]), 2
    From Policy
    JOIN Client ON Client.CLIENTID = Policy.CLIENTID
    Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote'
)
Order By Ordering, CLIENT.NAME

分组集

我注意到您在这里所做的只是第一个结果的汇总。因此,您实际上可以使用GROUPING SETS syntax 来获得您想要的结果,而无需额外查询。它会更有效率:

select Policy.[Effective Date], Policy.[Policy #], ISNULL(CLIENT.[NAME], 'Totals') AS Name, SUM(Policy.[Premium])
From Policy
JOIN Client ON Client.[CLIENTID] = Policy.[CLIENTID] 
Where Policy.[Effective Date] > '2000-11-11' AND Policy.[Policy Type] <> 'Quote'
GROUP BY GROUPING SETS (
    (Policy.[Effective Date], Policy.[Policy #], CLIENT.[NAME], Policy.[Premium]),
    ()
)
ORDER BY
    GROUPING_ID(Policy.[Effective Date], Policy.[Policy #], CLIENT.[NAME], Policy.[Premium]),
    CLIENT.[NAME]

function GROUPING_ID 为该行中聚合的每一列返回一个 1 位,因此对于我们的总数,我们得到位 1111,它排在 0000 之后以获取其余结果。

【讨论】:

我喜欢“分组集”。有没有办法为客户名称和高级添加列标题?由于“名称”似乎不起作用 已经编辑了。还有GROUP BY ROLLUP(col1,col2,col3),但它为每个级别做了一个小计,这不是你问的 太棒了! 2天我一直试图弄清楚这一点。我见过提到的分组集,但总是作为更复杂场景的一部分。非常感谢!

以上是关于如何在 T-SQL 中处理具有“Union All”但让第二个“Select”始终出现在底部的查询?的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL谜题:将表的每一行作为内联函数的输入传递,并使用UNION ALL开发新的堆栈数据集

如何在 Access 中对表的所有列进行 UNION ALL

如何仅在没有子查询的 UNION ALL 中按一个查询排序

sql中union 和 union all的区别

如何获取不在内部连接sql中的列,使用union all是很多时间

SqlServer中union 和 union all的区别