0

次のサンプル問題を使用して SQL Server で作業しています。Brandon は PC と Mac を好み、Sue は PC のみを好み、Alan は Mac を好みます。データは次のように表されます。ここでいくつかの妥協をしなければなりませんでしたが、うまくいけば、あなたは写真を手に入れることができます:

表 1: ユーザー

uID (INT PK), uName (VARCHAR)
1        'Brandon'
2        'Sue'
3        'Alan'

表 2: コンピュータ

cID (INT PK), cName (VARCHAR)
1        'Mac'
2        'PC'

表 3: UCPref -- 各ユーザーのコンピュータ設定を保存

uID (INT FK), cID (INT FK)
1        1
1        2
2        1
3        2

ここで、PC または Mac が好きな人をすべて選択したい場合、それは非常に簡単です。それを行う方法はたくさんありますが、アイテムのリストを入力している場合、IN 句は非常に簡単です。

SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE cID IN (1,2)

私が抱えている問題は、PC と Mac の両方が好きな人だけを選択したい場合にどうなるかということです。複数のサブクエリで実行できますが、それほどスケーラブルではありません。

SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE u.uID IN (SELECT uID FROM UCPref WHERE cID = 1)
AND u.uID IN (SELECT uID FROM UCPref WHERE cID = 2)

何百、何千もの異なる種類のコンピューターが存在する可能性があることを考慮して、複数のコンピューターを好むユーザーを返すことができるように、このクエリをどのように記述しますか (つまり、サブクエリはありません)。IN 句を変更して、「ALL」などのキーワードを使用して、括弧内にすべての項目を含むレコードのみを照合することを示すことができれば?

SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE cID IN *ALL* (1,2)
4

1 に答える 1

0

JOIN の使用:

SELECT u.uname
  FROM USERS u
  JOIN UCPREF ucp ON ucp.uid = u.uid
  JOIN COMPUTER mac ON mac.cid = ucp.cid
                   AND mac.cname = 'Mac'
  JOIN COMPUTER pc ON pc.cid = ucp.cid
                  AND pc.cname = 'PC'

同じテーブルに 2 回 JOIN しているため、テーブル エイリアスを使用しています。

EXISTS の使用:

SELECT u.uname
  FROM USERS u
  JOIN UCPREF ucp ON ucp.uid = u.uid
 WHERE EXISTS (SELECT NULL
                 FROM COMPUTER c
                WHERE c.cid = ucp.cid
                  AND c.cid IN (1, 2)
             GROUP BY c.cid 
               HAVING COUNT(*) = 2)

IN句を使用する場合は、使用する必要GROUP BY/HAVINGがありますが、COUNT() にはリスクがあります。一部のデータベースでは * 以外は許可されていませんが、MySQL では許可されていますDISTINCT ...。問題は、カウントで使用できない場合DISTINCT、値 2 の 2 つのインスタンスを取得する可能性があり、SQL に対して有効であり、誤検知が発生することです。

于 2009-11-18T01:30:04.200 に答える