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 BYorHAVINGステートメントで使用できますが、 SELECTorステートメントでは使用できませんWHERE。これは、プログラムがすべての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 には、エイリアスの使用に関する特定のルールが異なります。

EDIT 読者に論理句シーケンスを思い出させる目的は、多くの場合 (常にではありません)、エイリアスが宣言された句の後にのみエイリアスが参照可能になることです。最も一般的なのは、句で宣言されたエイリアスをSELECT句で使用できることORDER BYです。特に、句で宣言されたエイリアスは、同じ句SELECT内で参照できません。SELECT

ただし、製品の違いにより、すべての dbms がこのように動作するわけではないことに注意してください。

于 2016-01-22T21:13:04.023 に答える
3

仮想リレーションが実際に作成されるまで、エイリアスは使用できません。エイリアス自体を使用して追加の式を実行する場合は、その上で追加のクエリを実行するよりも、サブクエリとして使用して仮想リレーションを作成する必要があります。したがって、クエリを次のように変更します。

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;
)

2 番目のクエリが機能した理由をここに追加したいと思います。これは、クエリ プランナーが、クエリ元のテーブルで直接定義されている列を認識したためです。

于 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 に答える