是否有可能以这种方式使用AGG函数的SQL查询?

时间:2011-10-23 23:51:06

标签: sql postgresql aggregate-functions ansi-sql

假设我有以下聚合函数:

  • 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中,但不会在结果集中返回。

理想情况下,我想要一个DB不可知的解决方案的答案,但如果我必须绑定到db,我使用的是PostgreSQL(v9.x)。

修改

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

我想知道的主要问题是使用AGG功能的选择查询是否可以:

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

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

3 个答案:

答案 0 :(得分:1)

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

如果您只有分组值AGG1(param1), AGG2(param2),则可以在不提供明确GROUP BY子句的情况下离开。由于您混合了分组和非分组列,因此必须提供GROUP BY子句,其中包含SELECT中显示的所有非分组列。任何版本的PostgreSQL都是如此。阅读GROUP BY and HAVING it in the manual

从版本 9.1 开始,但是,在GROUP BY中列出主键后,您可以跳过此表的其他列,并仍在SELECT列表中使用它们。 release notes for version 9.1告诉我们:

  

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

关于参数

您打算将常量值提供给聚合函数吗?重点是什么? docs tell us

  

聚合函数计算来自多个输入行的单个结果。

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

作为针对SQLi的安全措施,使用USING $1, $2语法和列名称​​名称的名称

答案 1 :(得分: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原因移动到派生表(内部查询)

答案 2 :(得分:0)

这应该从高层次的角度来看,除了你在GROUP BY语句中需要COL1,COL2等,否则它们在SELECT列表中无效。在SELECT列表中使用AGG1等而不是在HAVING中不是问题。

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