在GROUP BY

时间:2016-03-04 14:13:56

标签: sql postgresql

这是我的疑问:

SELECT d.DeptName, CASE WHEN e.WorkCity is NULL THEN 'Mobile'
                                           ELSE 'Stationary'
                        END AS EmpType,
        AVG(e.MonthlyPayScale) AS AvgMnthPay
FROM Department d, Employee e
WHERE d.DeptId = e.DeptId
GROUP BY d.DeptName, EmpType
ORDER BY d.DeptName, EmpType

这是我的输出似乎是正确的:

 deptname |  emptype   |       avgmnthpay
----------+------------+------------------------
 EvanDept | Mobile     |  7500.0000000000000000
 MaxDept  | Stationary | 11250.0000000000000000
 PaulDept | Mobile     |  5000.0000000000000000
 PaulDept | Stationary | 12500.0000000000000000
(4 rows)

按部门名称和移动/固定员工分组,计算每个组员工的平均月工资。

据我所知,这是SQL查询的排序:

FROM
WHERE
GROUP BY
SELECT
ORDER BY

因此GROUP BY语句在SELECT语句之前发生 。那么为什么:

GROUP BY d.DeptName, EmpType

了解有关EmpType的任何信息,这是在SELECT语句中的CASE语句中声明的吗?

基本上,为什么在SELECT之前评估GROUP BY时我的代码是否有效?

3 个答案:

答案 0 :(得分:1)

在派生表中执行CASE表达式:

select DeptName, EmpType, AVG(MonthlyPayScale) AS AvgMnthPay
FROM
(
  SELECT d.DeptName as DeptName,
         CASE WHEN e.WorkCity is NULL THEN 'Mobile'
              ELSE 'Stationary'
         END AS EmpType,
         e.MonthlyPayScale as MonthlyPayScale
  FROM Department d
      JOIN Employee e ON d.DeptId = e.DeptId
)
GROUP BY DeptName, EmpType
ORDER BY DeptName, EmpType

还切换到现代的,明确的JOIN语法。更容易编写(没有错误),更易于阅读和维护,并且如果需要也更容易转换为外部联接!

答案 1 :(得分:1)

答案是Postgresql中的名称解析允许这样做。

从Postgresql 9.3的文档(第7.2.3节.GROUP BY和HAVING子句):

  

在严格的SQL中,GROUP BY只能按源表的列进行分组   但PostgreSQL对此进行了扩展,以允许GROUP BY按列分组   在选择列表中。按值表达式分组而不是简单   列名也是允许的。

Link

答案 2 :(得分:0)

您描述的处理通常用于解释查询的编译以及何时知道哪些标识符。 SQL Server对此非常明确,并且他们的规则记录在here

仅仅因为SQL Server以这种方式执行,并不意味着所有数据库都是这样做的。

因此,不同的数据库在允许各个子句中的列别名方面更好或更差。 MySQL和Postgres允许GROUP BYHAVING子句中的列别名; Oracle和SQL Server没有。所有数据库都允许ORDER BY中的列别名。实际上,有些内容(例如Hive)需要列别名,并且不允许聚合函数。

我确信ANSI标准对此主题有话要说。它是否真的是明确的是另一个问题,但不同的数据库有不同的个性。

并且,此讨论涉及查询的词汇分析。实际执行顺序与原始语句无关。大多数数据库引擎使用数据流引擎,数据流运算符和SQL结构之间没有一对一的对应关系。