分组在聚合参数和 NULL 替换中设置列

Posted

技术标签:

【中文标题】分组在聚合参数和 NULL 替换中设置列【英文标题】:Grouping sets columns in aggregate arguments and NULL replacement 【发布时间】:2016-01-29 15:39:49 【问题描述】:

互联网上有很多分组集示例,例如下面示例中的查询 Q1。但是查询 Q2 不同,因为 A2 是一个分组列,它被用作 SUM() 的参数。

根据 SQL 标准(自 2003 年以来的任何版本,支持分组集),以下哪一项对于 Q2 是正确的?如果(1)正确,请参照标准说明原因。

    A2 被 NULL 替换,除非它位于聚合的参数中。这种解释将给出以下结果 R1。这是 Oracle 的行为(似乎更有用)。

    A2 被 NULL 替换,包括它在聚合中的使用位置:这意味着聚合将返回 NULL。 这种解释将给出以下结果 R2。这就是我对 SQL 标准的理解(可能不正确)。

示例代码:

-- Setup
create table A (A1 int, A2 int, A3 int);
insert into A values (1, 1, 100);
insert into A values (1, 2, 40);
insert into A values (2, 1, 70);
insert into A values (5, 1, 90);

-- Query Q1
-- Expected/Observed results:
--
--         A1         A2    SUM(A3)
-- ---------- ---------- ----------
--          1          -        140
--          2          -         70
--          5          -         90
--          -          1        260
--          -          2         40
--          -          -        300
select A1, A2, sum (A3)
from A
group by grouping sets ((A1), (A2), ())
order by 1, 2;

-- Query Q2
-- Results R1 (Oracle):
--         A1         A2    SUM(A2)
-- ---------- ---------- ----------
--          1          -          3
--          2          -          1
--          5          -          1
--          -          1          3
--          -          2          2
--          -          -          5
-- 
-- Results R2 (SQL Standard?):
--         A1         A2    SUM(A2)
-- ---------- ---------- ----------
--          1          -          - 
--          2          -          - 
--          5          -          - 
--          -          1          3
--          -          2          2
--          -          -          -   -- NULL row
select A1, A2, sum (A2)
from A
group by grouping sets ((A1), (A2), ())
order by 1, 2;

我从 SQL 2003 7.9 Syntax 17 中了解到这一点,它描述了如何用 NULL 替换列。但是,我可能错过或误解了其他地方排除聚合参数的规则。

m) For each GS_i:
   iii) Case:
        1) If GS_i is an <ordinary grouping set>, then
           A) Transform SL2 to obtain SL3, and transform HC to obtain
              HC3, as follows:
              II) Replace each <column reference> in SL2 and HC that
                  references PC_k by "CAST(NULL AS DTPCk)"

【问题讨论】:

我没有看到问题。 @JuanCarlosOropeza 我的问题在最后——“我是否遗漏了 SQL 标准中的某些内容?或者 Oracle 在这里是非标准的?”。我会考虑改写一下... 我认为您写了很多,但没有指出您遇到的问题。似乎有什么不同,但不知道你认为哪一个是错误的。 我的假设是当PC_k 包含在聚合中时,用CAST(NULL AS DTPCk) 替换PC_k 不适用。您使用 Oracle 获得的结果与使用 SQL Server 获得的结果相同,并且在聚合中替换值的逻辑结果会改变聚合的含义。但是,我已经(痛苦地)通读了标准的相关部分,但找不到对该规则的明确引用,我怀疑它在某处被引用,但我现在对阅读标准失去了耐心...... 【参考方案1】:

与许多困难的 SQL 功能一样,查看标准的早期版本可能会有所帮助,其中措辞可能更简单。事实证明,分组集是在 SQL 1999 中引入的,然后在 SQL 2003 中进行了修订。

SQL 1999

语法规则 4 规定:

Let SING be the <select list> constructed by removing from SL every <select
sublist> that is not a <derived column> that contains at least one <set
function specification>.

然后语法规则 11 将 PC_k 定义为分组依据列表中包含的列引用。它构造一个派生表投影GSQQL_i 的并集,它们是投影PC_k 或NULL 的查询规范,PCBIT_i 分组函数指示符和SING

因此,任何包含 set 函数的参数都不会被替换,其列也不会被替换。所以答案(1)是正确的。

但是,在以下查询中,对应于 &lt;grand total&gt;GSQQL_i 不按 C1 分组,因此我认为它会给出错误,而不是用 NULL 替换该分组集的 C1。

select C1 + MAX(C2) from T group by grouping sets ((C1), ());

SQL 2003 - 2011

我仍然没有明确的答案。它取决于替换规则中“引用”的含义(或忘记指定?)。如果它表示 ISO 9075-1(SQL 第 1 部分:框架)中定义的“立即包含”、“简单包含”或“直接包含”中的一种,会更清楚。

一般规则开头的注释(SQL 2003 中的编号 134)说“作为 此语法规则中指定的语法转换的结果 子句,只剩下原始的 需要考虑。”所以 聚合参数要么已经被替换,要么实际上没有被替换:我们没有 期望以特殊方式评估聚合(而如果在语法规则 17 的 NULL 替换之前应用了一般规则 3,那么答案 (1) 将是正确的)。

我找到了一份技术勘误 5 [pdf] 的草稿,它是对 SQL 2003 的“差异”。这包括对第 80-87 页的相关更改。不幸的是,大部分更改只有一个简短的理由“提供对 CUBE 和 ROLLUP 的正确、统一的处理”。上面引用的一般规则 3 的基本原理是“澄清列引用的语义”。

【讨论】:

以上是关于分组在聚合参数和 NULL 替换中设置列的主要内容,如果未能解决你的问题,请参考以下文章

在 Tablesorter 中设置列​​宽

可以在实体框架中设置列排序

如何在 tableLayoutPanel 中设置列​​跨度

在 Oracle APEX 交互式网格中使用 JavaScript 从应用程序项中设置列值

如何在 Windows 窗体 (C#) 中设置列​​表框的确切高度?

添加新列时在alembic中设置列顺序