3

假设我有以下聚合函数:

  • AGG1
  • AGG2
  • AGG3
  • AGG4

是否可以像这样编写有效的 SQL(以与 db 无关的方式):

SELECT [COL1, COL2 ....], AGG1(param1), AGG2(param2) FROM [SOME TABLES]
WHERE [SOME CRITERIA]
HAVING AGG3(param2) >-1 and AGG4(param4) < 123
GROUP BY COL1, COL2, ... COLN
ORDER BY COL1, COLN ASC
LIMIT 10

其中 COL1 ... COLN 是正在查询的表中的列,param1 ... paramX 是传递给 AGG 函数的参数。

注意: AGG1 和 AGG2 在结果中作为列返回(但不会出现在 HAVING CLAUSE 中,AGG3 和 AGG4 出现在 HAVING CLAUSE 中但不会在结果集中返回。

理想情况下,我想要一个与数据库无关的解决方案答案,但如果我必须绑定到一个数据库,我使用的是 PostgreSQL (v9.x)。

编辑

澄清一下:我不反对在查询中使用 GROUP BY。我的 SQL 不是很好,所以上面的示例 SQL 可能有点误导。我已经编辑了上面的伪 sql 语句,希望能让我的意图更清楚。

我想知道的主要事情是使用 AGG 函数的选择查询是否可以:

  • 在返回的列中有 agg 函数值,而不在 HAVING 子句中指定它们。
  • 在 HAVING 子句中指定了 agg 函数,但未在结果集中返回。

从我目前收到的答案来看,这两个问题的答案似乎都是肯定的。为了更正我的 SQL,我唯一要做的就是添加一个 GROUP BY 子句以确保返回的行是唯一的。

4

3 回答 3

1

PostgreSQL 主要版本包括点后的第一个数字,因此“PostgreSQL (v9.x)”不够具体。正如@kekekela 所说,没有(便宜的)完全与数据库无关的方式。即使在 PostgreSQL 9.0 和 9.1 之间,也存在重要的语法差异。

如果您只有分组值AGG1(param1), AGG2(param2),您将无需提供明确的GROUP BY子句就可以逃脱。由于您混合了分组列和非分组列,因此您必须提供一个GROUP BY子句,其中包含出现在SELECT. 对于任何版本的 PostgreSQL 都是如此。在手册中阅读有关GROUP BY 和 HAVING 的信息。

但是,从版本9.1开始,一旦您在 中列出主键,GROUP BY您就可以跳过此表的其他列,并且仍然在SELECT列表中使用它们。9.1 版的发行说明 告诉我们:

当在 GROUP BY 子句中指定主键时,允许查询目标列表中的非 GROUP BY 列 (Peter Eisentraut)

关于参数

您是否打算将常量值提供给聚合函数?重点是什么?文档告诉我们

聚合函数从多个输入行计算单个结果。

还是您希望这些参数是列名?只要语句是在提交到数据库之前生成的,这种动态 SQL 就可以工作。不适用于准备好的语句或简单的sqlplpgsql函数。为此,您必须在函数中使用EXECUTE 。plpgsql

作为对 SQLi 的保护措施,使用USING $1, $2的语法和quote_ident()的列或表

于 2011-10-24T03:24:23.487 回答
1

在不使用 GROUP BY 的情况下聚合列的唯一方法是使用窗口函数。您遗漏了问题的详细信息,但以下内容可能是您要查找的内容:

SELECT *
FROM (
    SELECT [COL1, COL2 ....], 
           AGG1(param1) over (partition by some_grouping_column) as agg1, 
           AGG2(param2) over (partition by some_grouping_column) as agg2,
           row_number() over () as rn
    FROM [SOME TABLES]
    WHERE [SOME CRITERIA]
    ORDER BY COL1
)  t
WHERE AGG3 >-1 
  AND AGG4 < 123
  AND rn <= 10
ORDER BY col1

这是标准的 ANSI SQL,适用于大多数数据库,包括 PostgreSQL(从 8.4 开始)。

请注意,您不需要对 partition by 子句中的两个聚合使用相同的分组列。

如果您想坚持使用 ANSI SQL,那么您应该使用该row_number()函数来限制结果。如果您仅在 PostgreSQL(或LIMIT以某种方式支持的其他 DBMS)上运行它,则将 LIMIT 原因移动到派生表(内部查询)中

于 2011-10-24T07:00:54.120 回答
0

这应该从高层次的角度工作,除非您在 GROUP BY 语句中需要 COL1、COL2 等,否则它们在 SELECT 列表中将无效。在 SELECT 列表中而不是在 HAVING 中有 AGG1 等不是问题。

就 db 不可知论而言,无论你做什么,你都必须调整语法(例如,我不知道在 PostgreSQL、SQL SERVER 和 Oracle 中的 LIMIT 会有所不同),但是你如果您的高级表示是可靠的,则可以构建逻辑来正确地为每个语句构建语句。

于 2011-10-23T23:54:09.803 回答