2

私は SQL が苦手で、解決方法がわからない問題に遭遇しました。SQL に関する本 (O'Reilly's Learning SQL) の一部を読んで再読しましたが、必要な情報が含まれていると期待していましたが、見つかりませんでした。

私の問題は次のとおりです。簡単に説明できるように、簡単な例を使用します。

car、rim、および 2 つの組み合わせである carRim という 3 つのテーブルがあります。

car
    carId
    description

rim
    rimId
    description

carRim
    carRimId
    carId
    rimId
    price

テーブル carRim には、価格の追加属性があります。これは、リムの価格が車の種類ごとに異なる可能性があるためです。私が持っている制約は、すべてのタイプのリムをすべてのタイプの車に一度だけ結合する必要があるということです. したがって、car-rim のすべての組み合わせは一意である必要があります。

車にリムを追加したい場合、その車にまだ結合されていないリムのリストが必要です。このためには、リムの合計リストと、リムを追加したい車に既に結合されている carRim のリストに対して、それぞれリム テーブルと carRim テーブルが必要だと思います。

特定の車に結合されているリムのリストを作成する (単純な) クエリを作成しました。次の例では、carId 9 の車です。

SELECT
    * 
FROM
    rims 
INNER JOIN
    carRims 
ON
    carRims.rimId = rim.rimId 
WHERE
    carRims.carId = 9 

しかし今、特定の車にまだ結合されていないリムのリストが必要です。問題は、LEFT OUTER JOIN を実行すると、取得したリストが他の車へのリムの結合で「汚染」されるため、「WHERE carRims.carId IS NULL」のフィルター条件が機能しないことです。

SELECT
    * 
FROM
    rims 
LEFT OUTER JOIN
    carRims 
ON
    carRims.rimId = rim.rimId 
WHERE
    carRims.carId IS NULL

もう 1 つの課題は、クライアントが MySQL 4 を使用しており、現時点ではアップグレードできないため、サブクエリなど、MySQL 5 の新しい構文を使用できないことです。

この問題に対するクエリを MySQL 4 で作成できますか? 私はできると思います。

ありがとう!

4

3 に答える 3

2
SELECT  *
FROM    rims r
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    carRims cr
        WHERE   cr.rimId = r.RimId
                AND cr.carID = 9
        )

アップデート:

NOT EXISTSをaに書き換えるには、すべての条件を結合の句LEFT JOIN / IS NULLに入れる必要があります。ON

SELECT  r.* 
FROM    rims r
LEFT OUTER JOIN
        carRims cr 
ON      cr.rimId = r.rimId 
        AND cr.crID = 9
WHERE   cr.carId IS NULL
于 2010-01-25T15:29:58.703 に答える
1

左外部結合ON式に追加条件を入れることができます。あなたが欲しいのは、あなたの列carRims一致し、9号車に属する列ですよね?rims

SELECT
    * 
FROM
    rims 
LEFT OUTER JOIN
    carRims 
ON
    carRims.rimId = rim.rimId 
    AND carRims.carId = 9
WHERE
    carRims.carId IS NULL

他の車に他がある場合は、句carRimsの追加条件によって除外されます。ON


JOINorWHERE句のどこに条件を配置するかについての質問については、次のとおりです。

外部結合の場合、比較をどこに置くかが重要です。JOIN 句の条件は、1 つのテーブルの行が他のテーブルの行と一致するかどうかをテストするためのものです。一致をテストした後にそれぞれのテーブルの行をどうするかは、結合の種類によって異なります。

外部結合の場合、rimsに一致する行がない場合でも からの行が必要carRimsです。節に carID=9 条件を入れるとどうなるWHEREでしょうか?

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID
WHERE c.carID = 9

外部結合は からのすべての行を返し、 からのrims行はcarRimsと一致し、スプリアス値rimID含む行が含まれます。どの車も特定のリムに一致しないcarID場合にのみ、列に NULL を使用します。c.*

ただし、WHERE句は、値が 9 でない限り、結合の結果のすべての行を削除しcarIDます。つまり、carIDis NULL も削除されます。つまり、どの車にも一致しないリムの行も削除されます。したがって、結果は の結果と同等になりINNER JOINます。

carRimsそのため、行が に結合される前に、間違った carID を持つ行を から除外する必要がありrimsます。

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID AND c.carID = 9

その個々のテーブルのどの行が他の結合されたテーブルの行と一致できるかについての条件です。

ON多くの本では、句と句の間で条件を自由に組み合わせることができると書かれていますWHERE。しかし、これはすべての場合に当てはまるわけではありません。INNER JOIN最終結果はどちらの方法でも同じであるため、これは で機能します。これは、左結合の左テーブルのみに適用される条件にも機能します。たとえば、次のようになります。

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID AND r.make = 'ABC Rims'

FROM rims r LEFT OUTER JOIN carRims c ON r.rimId = c.rimID 
WHERE r.make = 'ABC Rims'

左外部結合の右側のテーブルの条件の場合、条件をどこに置くかが問題になります。


あなたが言ったことに対するもう1つのコメント:

私が持っている制約は、すべてのタイプのリムをすべてのタイプの車に一度だけ結合する必要があるということです. したがって、car-rim のすべての組み合わせは一意である必要があります。

それで、あなたはUNIQUE制約を宣言しましたcarRims(carId,rimId)か?

于 2010-01-25T15:34:19.790 に答える
0

(コメントには十分な文字がありませんでした)

@Bill Karwinあなたが提供したクエリは、私の問題に対する正しい答えです。ありがとう!

私が欲しかったのは、特定の車に接続されていない行 (リム) のリストでした。

「Learning SQL」の本で、クエリ内のフィルター条件と結合条件の場所は重要ではないことを読みました。彼らは、1 つの結合条件 (ON 句の後) と 1 つのフィルター条件 (WHERE 句の後) がある内部結合の例を示しました。これらの 2 つの条件を ON 句の後に配置するか、WHERE 句の後に配置するかは事実上問題ではないことを示しました。

それを念頭に置いて、私はあなたのソリューションの一部を理解していません。条件が

carRims.carId = 9

そして条件

carRims.carId IS NULL

両方とも存在しますが、結果セットが空になりませんか? どのフィールドも同時に 9 と NULL になることはできないからですよね?

私の疑念は次のとおりです。JOIN 句の条件場所にバインドされており、それらを WHERE 句に入れることはできません。

これは正しいです?

于 2010-01-25T15:58:35.863 に答える