いくつかの基準に基づいて行を選択したいが、基準に一致する行がない場合は最初の行を返したい
より短い(そして正しい)
WHERE
実際には句はまったく必要ありません。
SELECT street, zip, city
FROM address
ORDER BY street !~~ 'Test%', ord
LIMIT 1;
!~~
の Postgres 演算子ですNOT LIKE
。どちらでも使用できます。ロジックを (NOT LIKE
の代わりにLIKE
) 反転することで、デフォルトASC
の並べ替え順序と NULL の並べ替えを最後に使用できるようになったことに注意してください。これは重要な場合があります。読む。
これは短くなります (ただし、必ずしも高速であるとは限りません)。また、 @Gordon によって現在受け入れられている回答とは微妙に異なります (より信頼性が高くなります) 。
式で並べ替えるboolean
ときは、それがどのように機能するかを理解する必要があります。
現在受け入れられている回答ではORDER BY <boolean expression> DESC
、NULL を最初にソートする を使用しています。このような場合、通常は次を追加する必要がありますNULLS LAST
。
street
定義されている場合NOT NULL
、これは明らかに無関係ですが、質問では定義されていません。(常にWHERE
テーブル定義を提供してください。)現在受け入れられている回答では、句で NULL 値を除外することで問題を回避しています。
他の RDBMS (MySQL、Oracle など) には、boolean
Postgres のような適切な型がないため、それらの製品の使用者からの誤ったアドバイスがよく見られます。
現在のクエリ (および現在受け入れられている回答)には、句が必要ですWHERE
- または少なくともNULLS LAST
. ORDER BY
どちらでも違う表現をする必要はありません。
さらに重要なのは、複数の行が一致している場合street
(これは予想されることです)、返される行は任意であり、呼び出し間で変更される可能性があります。これは一般的に望ましくない効果です。このクエリは、タイを破る最小の行を選択しord
、安定した結果を生成します。
この形式は、 の行の存在に依存しないという点でも柔軟性がありord = 0
ます。代わりに、最小の行ord
がいずれかの方法で選択されます。
インデックスで高速化
(それでも正しいです。) 大きなテーブルの場合、次のインデックスを使用すると、このクエリのパフォーマンスが大幅に向上します。
CREATE INDEX address_street_pattern_ops_idx ON address(street text_pattern_ops);
詳細な説明:
未定義の詳細によっては、インデックスに列を追加するのに費用がかかる場合があります。
このインデックスを使用した最速のクエリ:
(
SELECT street, zip, city
FROM address
WHERE street LIKE 'Test%'
ORDER BY ord -- or something else?
-- LIMIT 1 -- you *could* add LIMIT 1 in each leg
)
UNION ALL
(
SELECT street, zip, city
FROM address
ORDER BY ord
-- LIMIT 1 -- .. but that's not improving anything in *this* case
)
LIMIT 1
ところで、これは単一のステートメントです。
これはより冗長ですが、より単純なクエリ プランを使用できます。最初の行が十分な行を生成する場合 (この場合は 1) 、 2 番目SELECT
の行UNION ALL
は実行されません。SELECT
でテストすると、クエリ プランにEXPLAIN ANALYZE
表示されます。(never executed)
詳細:
の評価UNION ALL
ゴードンのコメントへの返信。ドキュメントごと:
同じステートメント
内の複数UNION
の演算子は、括弧で特に指定されていない限り、左から右に評価されます。SELECT
大胆強調鉱山。
またLIMIT
、十分な行が見つかるとすぐに Postgres の評価を停止します。そのため(never executed)
、 の出力に が表示されますEXPLAIN ANALYZE
。
ORDER BY
final の前にアウターを追加すると、LIMIT
この最適化は不可能になります。次に、どの行が最初にソートされるかを確認するために、すべての行を収集する必要があります。