12

我可以修改下一个以使用列别名avg_timecnt表达式ROUND(avg_time * cnt, 2)吗?

SELECT 
    COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time, 
    MAX(time) as max_time, 
    ROUND(AVG(time), 2) as avg_time, 
    MIN(time) as min_time, 
    COUNT(path) as cnt, 
    ROUND(avg_time * cnt, 2) as slowdown, path
FROM 
    loadtime
GROUP BY
    path
ORDER BY
    avg_time DESC
LIMIT 10;

它引发了下一个错误:

ERROR:  column "avg_time" does not exist
LINE 7:  ROUND(avg_time * cnt, 2) as slowdown, path

然而,下一个工作正常(使用主表达式而不是列别名:

SELECT 
    COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time, 
    MAX(time) as max_time, 
    ROUND(AVG(time), 2) as avg_time, 
    MIN(time) as min_time, 
    COUNT(path) as cnt, 
    ROUND(AVG(time) * COUNT(path), 2) as slowdown, path
FROM 
    loadtime
GROUP BY
    path
ORDER BY
    avg_time DESC
LIMIT 10;
4

4 回答 4

12

GROUP BY您可以在or语句中使用以前创建的别名,HAVING但不能在SELECTorWHERE语句中使用。这是因为程序SELECT同时处理所有语句并且还不知道别名的值。

解决方案是将查询封装在子查询中,然后别名在外部可用。

SELECT stddev_time, max_time, avg_time, min_time, cnt, 
       ROUND(avg_time * cnt, 2) as slowdown
FROM (
        SELECT 
            COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time, 
            MAX(time) as max_time, 
            ROUND(AVG(time), 2) as avg_time, 
            MIN(time) as min_time, 
            COUNT(path) as cnt, 
            path
        FROM 
            loadtime
        GROUP BY
            path
        ORDER BY
            avg_time DESC
        LIMIT 10
   ) X;
于 2016-01-22T21:06:28.680 回答
6

查询的执行顺序(以及因此表达式和别名的评估)与它的编写方式不同。“一般”位置是按以下顺序评估子句:

FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY

因此,在 select 子句完成之前,大多数查询都不知道列别名(这就是您可以在 ORDER BY 子句中使用别名的原因)。但是,在 from 子句中建立的表别名在 where to order by 子句中可以理解。

最常见的解决方法是将查询封装到“派生表”中

推荐阅读:SQL 查询的执行顺序

注意:不同的 SQL dbms 对于别名的使用有不同的具体规则

编辑 提醒读者逻辑子句序列的目的是,通常(但不总是)别名仅在声明别名的子句之后才变得可引用。其中最常见的是子句中声明的别名SELECT可以被ORDER BY子句使用。特别是,在子句中声明的别名SELECT不能在同一SELECT子句中引用。

但请注意,由于产品的差异,并非每个 dbms 都会以这种方式运行

于 2016-01-22T21:13:04.023 回答
3

在实际创建虚拟关系之前,别名不可用,如果您想使用别名本身执行其他表达式,则必须使用 as 子查询创建虚拟关系,而不是在其之上运行附加查询。因此,我会将您的查询修改为以下内容:

SELECT stddev_time, max_time, avg_time, min_time, ROUND(avg_time * cnt, 2) as slowdown, path FROM
(
SELECT 
    COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time, 
    MAX(time) as max_time, 
    ROUND(AVG(time), 2) as avg_time, 
    MIN(time) as min_time, 
    COUNT(path) as cnt, 
    ROUND(AVG(time) * COUNT(path), 2) as slowdown, path
FROM 
    loadtime
GROUP BY
    path
ORDER BY
    avg_time DESC
LIMIT 10;
)

我想在此处添加您的第二个查询起作用的原因是因为查询规划器识别出这些列直接在您查询它们的表中定义。

于 2016-01-22T21:13:25.543 回答
2

要么重复表达式:

ROUND(ROUND(AVG(time), 2) * COUNT(path), 2) as slowdown

或使用子查询:

SELECT *, ROUND(avg_time * cnt, 2) as slowdown FROM (
  SELECT 
    COALESCE(ROUND(stddev_samp(time), 2), 0) as stddev_time, 
    MAX(time) as max_time, 
    ROUND(AVG(time), 2) as avg_time, 
    MIN(time) as min_time, 
    COUNT(path) as cnt, 
    path
  FROM loadtime
  GROUP BY path) x
ORDER BY avg_time DESC
LIMIT 10;
于 2016-01-22T21:13:18.797 回答