序章
場合によっては、結合の代わりに意図的にスカラー サブクエリを使用して、複数の行が見つからないことを確認できます。たとえば、いくつかのperson
行の国籍を検索するために、このクエリを使用する場合があります。
select p.name,
c.iso
from person p
join person_country_map pcm
on p.id = pcm.person
join country c
on pcm.country = c.id
where p.id in (1, 2, 3)
ここで、person_country_map
が関数マッピングではないとします。特定の人物が複数の国にマップされる場合があるため、結合によって複数の行が検出される場合があります。または、実際には、少なくともデータベースの制約に関する限り、人物がマッピング テーブルにまったく含まれていない可能性があります。
しかし、この特定のクエリでは、クエリを実行している人物が 1 つの国しか持っていないことをたまたま知っています。それが私のコードの基礎となる仮定です。しかし、可能であればその仮定を確認したいと思います。何かがうまくいかず、複数の国を持つ人、または国のマッピング行がない人に対してこのクエリを実行しようとした場合、それは死ぬでしょう。
最大 1 行の安全性チェックを追加する
複数の行をチェックするには、結合をスカラー サブクエリとして書き直すことができます。
select p.name,
(
select c.iso
from person_country_map pcm
join country c
on pc.country = c.id
where pcm.person = p.id
) as iso
from person p
where p.id in (1, 2, 3)
現在、照会された人物が 2 つ以上の国にマップされている場合、DBMS はエラーを返します。単純な結合のように、同じ人物に対して複数のエントリが返されることはありません。そのため、行がアプリケーションに返される前であっても、このエラー ケースがチェックされていることを知っていると、少し楽に眠ることができます。もちろん、慎重なプログラマーとして、アプリケーションもチェックインすることがあります。
行が見つからない 場合に安全性をチェックすることは可能ですか?
しかし、 person_country_map に人物の行がない場合はどうなるでしょうか? その場合、スカラー サブクエリは null を返すため、左結合とほぼ同等になります。
(議論のために、 person_country_map.country から country.id への外部キーと、country.id の一意のインデックスを想定して、特定の結合が常に成功し、正確に 1 つの国の行を見つけるようにします。)
私の質問
1 つだけの結果が必要であることを SQL で表現できる方法はありますか? 単純なスカラー サブクエリは「0 または 1」です。言えるようになりたい
select 42, (select exactly one x from t where id = 55)
サブクエリが行を返さない場合、クエリは実行時に失敗します。もちろん、上記の構文は架空のものであり、それほど簡単ではないと確信しています。
私は MSSQL 2008 R2 を使用しています。実際、このコードはストアド プロシージャに含まれているため、必要に応じて TSQL を使用できます。(もちろん、ビュー定義でも使用できるため、通常の宣言型 SQL の方が望ましいです。)もちろん、チェックを実行することもexists
、値を選択して TSQL 変数に入れ、null かどうかを明示的にチェックすることもできます。結果を一時テーブルに選択し、そのテーブルにチェックとして一意のインデックスを作成することもできます。しかし、サブクエリが正確に 1 つの行を返すという私の仮定をマークし、その仮定を DBMS にチェックさせる、これ以上読みやすく洗練された方法はありませんか?