PostgreSQL-相関サブクエリが失敗しますか?
-
06-07-2019 - |
質問
次のようなクエリがあります:
SELECT t1.id,
(SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) as num_things
FROM t1
WHERE num_things = 5;
目標は、他のテーブルに5回出現するすべての要素のIDを取得することです。ただし、次のエラーが表示されます。
ERROR: column "num_things" does not exist
SQL state: 42703
私はデータベースについてはやや新しいので、おそらくここでばかげたことをしているでしょう。 num_things
にアクセスできるように、このクエリを修正する方法はありますか?または、そうでない場合、この結果を達成する他の方法はありますか?
解決
クエリを次のように書き換えることができると思います:
SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) = 5;
他のヒント
SQLの使用に関するいくつかの重要なポイント:
- WHERE句では列エイリアスを使用できませんが、HAVING句では使用できます。これがエラーの原因です。
- 相関サブクエリを使用するよりも、JOINとGROUP BYを使用すると、カウントをより効率的に実行できます。ずっと速くなります。
- HAVING句を使用してグループをフィルタリングします。
このクエリを記述する方法は次のとおりです。
SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;
Charles Bretanaのソリューションのように、このクエリはt1で JOIN
をスキップできることを理解しています。ただし、クエリにt1の他の列を含めることをお勧めします。
再:コメントの質問:
違いは、 GROUP BY
がグループをグループごとに1行に減らす前に、 WHERE
句が行で評価されることです。 HAVING
句は、グループが形成された後に評価されます。たとえば、 HAVING
を使用してグループの COUNT()
を変更することはできません。グループ自体のみを除外できます。
SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;
上記のクエリでは、 WHERE
は条件に一致する行をフィルターし、 HAVING
は少なくとも5つのカウントを持つグループをフィルターします。
ほとんどの人を混乱させるポイントは、 GROUP BY
句がないため、 HAVING
や< code> WHERE は交換可能です。
WHERE
は、選択リスト内の式の前に評価されます。 SQL構文は選択リストを最初に置くため、これは明らかではないかもしれません。したがって、 WHERE
を使用して行を制限することにより、多くの高価な計算を節約できます。
SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;
上記のようなクエリを使用する場合、select-list内の式はすべての行に対して計算され、 HAVING
のために結果のほとんどを破棄します調子。ただし、以下のクエリは、 WHERE
条件に一致する単一行の式のみを計算します。
SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;
要約すると、クエリは一連の手順に従ってデータベースエンジンによって実行されます。
-
JOIN
によって生成された行を含む、テーブルから行のセットを生成します。 - 行セットに対して
WHERE
条件を評価し、一致しない行を除外します。 - 行セット内のそれぞれについて、select-listの式を計算します。
- 列エイリアスを適用します(これは別のステップであるため、選択リストの式でエイリアスを使用できないことに注意してください)。
-
GROUP BY
句に従って、グループをグループごとに1行に圧縮します。 - グループに対して
HAVING
条件を評価し、一致しないグループを除外します。 -
ORDER BY
句に従って結果をソートします。
他のすべての提案は機能しますが、基本的な質問に答えるには、書くだけで十分です
SELECT id From T2
Group By Id
Having Count(*) = 5
PostgreSQLでは、having句でエイリアス列を使用する方法はありません。
i.e。
my_id = 1のユーザーからmy_idとしてusr_idを選択
うまくいきません。
機能しない別の例:
SELECT su.usr_id AS my_id、COUNT(*)AS val FROM sys_user AS su GROUP BY su.usr_id HAVING val&gt; = 1
同じエラーが発生します:val列は不明です。
これは、ビル・カーウィンがPostgresに実際には当てはまらない何かを書いたために強調されています:
&quot; WHERE句では列エイリアスを使用できませんが、HAVING句では使用できます。これがエラーの原因です。&quot;
これを試してください
SELECT t1.id,
(SELECT COUNT(t2.id) as myCount
FROM t2
WHERE t2.id = t1.id and myCount=5
) as num_things
FROM t1