假设我有以下聚合函数:
是否可以像这样编写有效的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功能的选择查询是否可以:
从我到目前为止收到的答案来看,这两个问题的答案似乎都是肯定的。我唯一想要纠正我的SQL就是添加一个GROUP BY子句以确保返回的行是唯一的。
答案 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就会起作用。不适用于预准备语句或简单sql
或plpgsql
函数。为此,您必须在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中会有所不同) ,但是你可以构建逻辑来为每个语句正确构造语句,只要你的高级表示是可靠的。