web-dev-qa-db-ja.com

優先度付きのクエリでORを使用する方法は?

のような単純なクエリで

SELECT * 
FROM table
WHERE id='x' OR id='y'

WHERE句の1つだけを取得するように優先順位を付けるにはどうすればよいですか?

id='x'で行を取得することを意味します。行がない場合のみ、id='y'で行を取得します。

つまり、id='y'の行がある場合はid='x'を使用しないでください。

5
Googlebot
SELECT * 
FROM   table
WHERE  id IN ('x', 'y')
AND    (id='x' OR NOT EXISTS(SELECT id FROM table WHERE id='x'))

トリックを実行する必要があります(警告:私はMSSQLの人であり、mySQLで試したことがありませんが、構文も問題なく受け入れられていると思われます)。ただし、効率は最初のフィルタリング句に一致する行の数によって異なります。 (id='x' OR id='y'に一致するすべての行について、EXISTS部分のサブクエリは、クエリプランナーが外部クエリの何にも依存しないことを確認できるほど明るくなければ、おそらく実行されます結果の再利用-期待されるのが2つだけの場合(これはidのような列名を使用している場合です)これは問題ではありません)

3
David Spillett

私もMySQLの人ではありませんが、これでうまくいくと思います。

SELECT SQL_CALC_FOUND_ROWS * 
FROM table
WHERE id='x' 
UNION ALL
SELECT * 
FROM table
WHERE FOUND_ROWS() = 0 AND id='y'

免責事項:これが文書化された/保証された動作であるかどうかはわかりません。

1
Martin Smith

あなたはUNION ALLおよびLIMIT

SELECT *
FROM table
WHERE id=x
  UNION ALL
  SELECT *
  FROM table
  WHERE id=y
ORDER BY id='x'
LIMIT 1;

とにかくPostgreSQLで動作します。

CREATE TABLE foo
AS
  SELECT
    x::int % 7 AS a,
    5 AS b
  FROM generate_series(1,1e6::int)
    AS gs(x);

CREATE INDEX ON foo (a);
ANALYZE foo;


explain analyze SELECT * FROM foo WHERE a=5 UNION ALL SELECT * FROM foo WHERE b = 5 LIMIT 1;
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..0.04 rows=1 width=8) (actual time=0.026..0.027 rows=1 loops=1)
   ->  Append  (cost=0.00..45287.67 rows=1143767 width=8) (actual time=0.025..0.025 rows=1 loops=1)
         ->  Seq Scan on foo  (cost=0.00..16925.00 rows=143767 width=8) (actual time=0.024..0.024 rows=1 loops=1)
               Filter: (a = 5)
               Rows Removed by Filter: 4
         ->  Seq Scan on foo foo_1  (cost=0.00..16925.00 rows=1000000 width=8) (never executed)
               Filter: (b = 5)
 Planning time: 0.203 ms
 Execution time: 0.061 ms
(9 rows)

(never executed)は、ジョブが完了したことを意味します。

0
Evan Carroll