ゼロ行が一致する場合でも、SELECTが定数値を返すようにする


15

次の選択ステートメントを検討してください。

SELECT *, 
       1 AS query_id 
FROM players 
WHERE username='foobar';

プレーヤーの他の列query_idとともに値を1持つ列を返します。

selectが一致する行を検出しなかった場合でも、上記のSQLに少なくともquery_idofを返させるにはどう1すればよいですか?

ところで、それはPostgreSQL 8.4です。

回答:


22
SELECT col1, 
       col2, 
       col3, 
       1 AS query_id 
FROM players 
WHERE username='foobar'
union all 
select null,
       null,
       null,
       1
where not exists (select 1 from players where username = 'foobar');

または代替として(かもしれない何秒副選択が必要とされないよう速くなります)。

with qid (query_id) as (
   values (1)
) 
select p.*, 
       qid.query_id
from qid 
  left join players as p on (p.useranme = 'foobar');

上記をよりコンパクトな表現に書き換えることができます。

select p.*, 
       qid.query_id
from (values (1)) as qid (query_id)
  left join players as p on (p.useranme = 'foobar');

ただし、明示的なCTE(with...)の方が読みやすいと思います(ただし、それは常に見る人の目にあります)。


1
最初の例を試してみると、ALLキーワードは不要なようです。
ナタナエルヴァイス

2
@NatWeiss:あなたが特定の順序が必要な場合、あなたが持って供給しますorder by。2番目は、正確に1行1列で仮想テーブルを「作成」し、外部結合を(「実際の」結合条件なしで)実行するため、少なくともその1行が常に返されます。select *本番コードでの使用はスタイルが悪いです。しないでください。常に必要な列をリストしてください。 アドホッククエリでのみ使用するselect *必要があります。
a_horse_with_no_name

2
@NatWeiss:「他の結合」の「代替構文」とは何ですか?そして、なぜあなたleft joinは読めないと思いますか?
a_horse_with_no_name

2
@NatWeiss:where句の暗黙的な結合はコーディングスタイルが悪いため、避ける必要があります。エラーを発生させることなく、不要なデカルト結合につながる可能性があります。また、参加とフィルタリングの2つの(リレーショナル)概念
-a_horse_with_no_name

4
再:必要に応じていない「労働組合」節の「すべて」修飾子は:UNION ALL時々よりも効率的な場合がありUNIONますが、明示的にどちらかあなたが出てくる重複行が存在しないことを期待することを問い合わせプランナを言っているように、UNIONエドクエリまたは場合それらを出力したいのです。ALL修飾子なしでは、DISTINCTキーワードと同じように(返される各行の1つだけ)重複行を削除することを前提とし、結果をさらに時間をかけて再スキャンする必要があることを保証します。したがって、出力行の重複排除が特に必要ALLUNIONない限り、withを使用します。
デビッドスピレット

7

1行または0行しか戻らないことを期待している場合、これも機能します。

SELECT
  max(col1) col1,
  max(col2) col2, 
  1 AS query_id 
FROM
  players 
WHERE
  username='foobar';

行が見つからない場合、query_idを除くすべての値がnullである1つの行を返します。


2
ナイストリック。唯一の欠点は、条件に一致するものが複数ある場合、col1とcol2の値が同じ行に属さない可能性があることですusername = 'foobar'
-a_horse_with_no_name

1
Coalesce()もこの方法で使用できますか?
ナタナエルヴァイス

1
Coalesceは、テーブルから何も投影されない行を生成しません。
デビッドアルドリッジ

1
@a_horse_with_no_nameはい。ただし、テーブル名と列名は、述語がテーブルの候補キーにあることを示唆しているため、0行または1行が投影されます。
デビッドアルドリッジ

3

ここで遅く鳴りますが、動作する構文があります(少なくとも9.2では、以前のバージョンを試していません)。

SELECT (COALESCE(a.*,b.*::players)).*
FROM ( SELECT col1,  col2,  col3, 1 AS query_id 
       FROM players WHERE username='foobar' ) a
RIGHT JOIN (select null col1, null col2, null col3, 1 col4) b
ON a.query_id = b.col4;

「a」の内容全体がヌルの場合にのみ、「ブランク」行を返します。

楽しい。/ bithead


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.