web-dev-qa-db-ja.com

WITH ... ASステートメントが期待どおりに機能しない

私はこのエラーを受け取ります:

WITH...AS syntax error

次のクエリを実行しようとすると発生します。

with expensive_service as (
    select s1.*
    from service s1, service s2
    where s1.price > s2.price
)
select * 
from service except expensive_service;

私は実装しようとしていました WITH ... AS (PostgreSQLドキュメントへのリンク)。

このクエリは、私が探している望ましい出力を私に与えます:

select * 
from service except ( 
    select s1.*
    from service s1, service s2
    where s1.price > s2.price
)

エラーがどこにあるか私に指示するどんな援助でも大歓迎です!

2
FernandoH-G

CTE(共通テーブル式)はビューのようなものであり、他のビュー(またはテーブル)のように扱う必要があります。 EXCEPTの2番目の部分として、完全なSELECTステートメントが必要です。

with expensive_service as (
    select s1.*
    from service s1, service s2
    where s1.price > s2.price
)
select * 
from service 
except 
select *
from expensive_service;

UNION、EXCEPT、またはINTERSECTの個々の部分を囲む括弧は不要です(onlyクエリにORDER BYが必要な場合を除きます)。 LIMIT句を使用しています)。

したがって、元のクエリは(私の意見では)、次のように書くこともできます

select * 
from service 
except  
select s1.*
from service s1, service s2
where s1.price > s2.price

このクエリは、私が探している望ましい出力を私に与えます:

代わりにこれを使用してください!

SELECT *
FROM   service
WHERE  price = (SELECT min(price) FROM service)
-- OR  price IS NULL  -- add if price can be NULL

テーブルが大きい場合は、(price)にインデックスがあることを確認してください。

現在受け入れられている回答には優れた技術情報がありますが、実際のクエリは使用しないでください。また、通常はEXCEPTではなくEXCEPT ALLが必要です。見る:

しかし、しないでください。

どうして?

2番目のSELECTの暗黙のCROSS JOINは、O(N²)でスケーリングされます。それは何をするためのものか?

...
SELECT s1.*
FROM   service s1, service s2
WHERE  s1.price > s2.price

これにより、テーブル内のpriceが小さい(またはprice IS NULL)の行ごとに、すべての行のコピーが1つ返されます。何のために?次のステップでそれらを除外します。つまり、価格が最も小さい行(またはprice IS NULL)のみが除外されません。言い換えると:

最小のprice(またはprice IS NULL)を持つすべての行を取得します。

関連:

2