【问题标题】:How to aggregrate without using `GROUP BY`?如何在不使用 `GROUP BY` 的情况下进行聚合?
【发布时间】:2012-01-26 19:16:41
【问题描述】:

我有如下查询

SELECT a.*, b.*

(SELECT ATTR1, ATTR2, sum(QUANTITY) AS TOTAL_QTY,
ATTR3 FROM TABLE_A
WHERE ATTR4 > 0
GROUP BY ATTR1, ATTR2, ATTR3) a,

TABLE_B b

WHERE a.ATTR1 = b.ATTR1
AND a.ATTR2 = b.ATTR2

我只需要GROUP BY ATTR1 来计算正确的TOTAL_QTY,但我将其他属性分组的唯一原因是因为Oracle 要求如果存在GROUP BY 子句,那么所有SELECT 属性都应该在GROUP BY 子句也是如此。

这意味着每次我需要来自 Table_A 的此查询中的属性时,我也需要将其放入 GROUP BY 中。这不仅看起来难看,而且可能会对性能产生影响,甚至可能产生无法预料的副作用。

如何重写上述查询以计算每个ATTR1 组中的TOTAL_QTY,而不使用GROUP BY 子句?

【问题讨论】:

  • 这是聚合的本质,你必须分组,否则系统不知道你想要总计什么或如何形成行。消除这种影响的唯一方法是在其他列 max(attr1)、max(attr2) 上使用聚合,但是您很快就会明白为什么如果 attr1 和 attr2 在不同的行中具有不同的值,group by 是更好的选择同一列
  • "Oracle 要求如果存在 GROUP BY 子句,那么所有 SELECT 属性也应该在 GROUP BY 子句中。"不正确 - 它们也可以聚合;如果对于所需分组项的给定值,其他值将始终保持不变,则可以使用诸如 MAX 之类的函数。
  • 您要查找的内容不明确。假设您有两行,attr1 的值相同,attr2 的值不同。在这种情况下,您希望结果集是什么样的?
  • @DaveCosta 在这种情况下,其中任何一个都可以。实际上在我的情况下,如果 attr1 是其他表的 FK。如果它出现多次,那么它们基本上都指向另一个表中的一行。 Table_a 记录每个实例的单独数量值。我只是想从 Table_a 中获取汇总信息和其他一些常见信息。

标签: sql oracle group-by aggregate-functions


【解决方案1】:

使用 Oracle 分析函数。将 table_a 的内联视图更改为:

select attr1,
       attr2,
       sum(quantity) over (partition by attr1 order by attr1) as total_qty,
       attr3
from   table_a
where  attr4 > 0

这可能需要稍作调整,但这是基本思想。

【讨论】:

  • 窗口聚合函数的向后兼容程度如何?只有11g? 10克?
  • +1 这种“内联聚合”技术也适用于 PostgreSQL 和 SQL Server 2005+
  • 这看起来很有希望。从来不知道这一点,但这里的问题是我将从一个组中获取所有行。我需要像GROUP BY 那样每组一行。
  • 此技术假设用户希望 table_a 中的每条记录都有一行,而不是 attr1 的每个不同值都需要一行。
  • @AppleGrew:所以,如果您希望 attr1 的每个不同值有 1 行,但您希望在结果集中包含 attr2,如果有 2 行attr1attr2 的值不同?
【解决方案2】:

试试:

SELECT a.*, b.*
from (SELECT ATTR1, 
             max(ATTR2) ATTR2, 
             sum(QUANTITY) AS TOTAL_QTY,
             max(ATTR3) ATTR3 
      FROM TABLE_A
      WHERE ATTR4 > 0
      GROUP BY ATTR1) a,
      TABLE_B b
WHERE a.ATTR1 = b.ATTR1
AND a.ATTR2 = b.ATTR2

(假设对于 ATTR1 的每个给定值,ATTR2 和 ATTR3 的值是恒定的 - 即它们在功能上依赖于它。)

【讨论】:

  • @AppleGrew:该答案似乎与您对 Dave Costa 对您问题的评论的回答相矛盾。是哪个?
  • 该评论仅适用于attr1。其他属性可能不同,也可能不同。
  • @AppleGrew:您需要重新阅读 Dave Costa 的评论 - 他说,“假设您有两行 attr1 的值相同,而 attr2 的值不同。什么您希望结果集在这种情况下看起来像吗?”您回答说:“在这种情况下,其中任何一个都可以”。
  • 对不起@Mark。我想我过度劳累了或什么的……我还是不明白你的意思。无论如何,非常感谢您的帮助。
  • 我想看看那些性能测试,因为这似乎不太可能。
【解决方案3】:

根据您对上面我的 cmets 的回复,听起来您希望每个 ATTR1 的值一组,并且您只需要属于该组的 ATTR2 的任何值。您只需在群组查询中将MAXMIN 应用于ATTR2 即可:

SELECT a.*, b.*
FROM
(SELECT ATTR1, max(ATTR2) attr2, sum(QUANTITY) AS TOTAL_QTY,
ATTR3 FROM TABLE_A
WHERE ATTR4 > 0
GROUP BY ATTR1, ATTR2, ATTR3) a,
TABLE_B b
WHERE a.ATTR1 = b.ATTR1
AND a.ATTR2 = b.ATTR2

这样,您可以从组中的所有成员中任意选择 ATTR2 的单个值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 2021-03-12
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多