3

私はスタンフォード大学で DB コースの紹介を行っていますが、これは宿題の 1 つです。私のコードはうまく機能しますが、同じ SELECT-FROM-JOIN 部分を 2 回再利用した方法があまり好きではありません。

SELECT name, grade
FROM Highschooler
WHERE
    ID IN (
        SELECT H1.ID
        FROM Friend
        JOIN Highschooler AS H1
            ON Friend.ID1 = H1.ID
        JOIN Highschooler AS H2
            ON Friend.ID2 = H2.ID
        WHERE H1.grade = H2.grade    
    ) AND
    ID NOT IN (
        SELECT H1.ID
        FROM Friend
        JOIN Highschooler AS H1
            ON Friend.ID1 = H1.ID
        JOIN Highschooler AS H2
            ON Friend.ID2 = H2.ID
        WHERE H1.grade <> H2.grade
    )
ORDER BY grade, name

これは、コードで使用される 2 つのテーブルの SQL スキーマです。

Highschooler(ID int, name text, grade int);
Friend(ID1 int, ID2 int);

同じ学年にしか友達がなく、他の学年には友達がいないすべての高校生にクエリを実行する必要がありました。以下のコードを 1 回だけ書き、2 つの異なる WHERE 句 = と <> に対して 2 回再利用する方法はありますか?

    SELECT H1.ID
    FROM Friend
    JOIN Highschooler AS H1
        ON Friend.ID1 = H1.ID
    JOIN Highschooler AS H2
        ON Friend.ID2 = H2.ID

編集: SQLite コードを提供する必要があります。

4

4 に答える 4

4

WHERE EXISTSこれは、クエリの「ポスターの子」の例です。

SELECT name, grade
FROM Highschooler ME
WHERE EXISTS (
    SELECT 1
    FROM Friend F
    JOIN Highschooler OTHER on F.ID2=OTHER.ID
    WHERE F.ID1=ME.ID AND OTHER.Grade = ME.GRADE
)
AND NOT EXISTS (
    SELECT 1
    FROM Friend F
    JOIN Highschooler OTHER on F.ID2=OTHER.ID
    WHERE F.ID1=ME.ID AND OTHER.Grade <> ME.GRADE
)

EXISTS条件は、1 つ以上の行trueを返すかどうかです。SELECTそれ以外の場合は ですfalse。内側のサブクエリを外側のサブクエリ (部分) と関連付け、必要F.ID1=ME.IDな残りの制約 (OTHER.Grade = ME.GRADEまたはOTHER.Grade <> ME.GRADE) をクエリに追加するだけです。

于 2013-02-10T16:14:57.613 に答える
4

これは、個人に関連するグループに関する典型的なタイプの質問です。このような質問に直面した場合、1 つのアプローチは結合を使用することです (物事をペアで見る)。多くの場合、より良いアプローチは、集約を使用してグループ全体を一度に調べることです。

ここでの洞察は、友達のグループがあり、全員が同じ学年である場合、最小と最大の学年は同じになるということです。

クエリを作成するには、そのヒントで十分かもしれません。もしそうなら、ここでやめてください。

必要なものを返すクエリは、実行していたものよりもはるかに単純です。友達の成績を見るだけです。

SELECT f.id1
FROM Friend f jJOIN
     Highschooler fh
     ON Friend.ID1 = fh.ID join
group by f.id1
having max(fh.grade) = min(fh.grade)

このhaving句により、すべてが同じになることが保証されます (NULL 値は無視されます)。

編集:

このバージョンは、次の質問に答えます: どの高校生に同じ学年の友達がいるか? あなたの質問はあいまいです。おそらく、友達元の人はすべて同じ学年です。もしそうなら、あなたは小さな修正でそうすることができます. having1 つの方法は、句を次のように変更することです。

having max(fh.grade) = min(fh.grade) and
       max(fh.grade) = (select grade from Highschooler h where f.id1 = h.id1)

これにより、友達元の人がすべて同じ学年であることが確認されます。

于 2013-02-10T16:16:47.507 に答える
1

一部のフィルタリング結合を UNION や MINUS/EXCEPT などのセット操作に変換すると、より自然なクエリ形状を取得できる場合があります。あなたのクエリは、たとえば(疑似コード)のように書くことができます:

  SELECT H.id
  FROM Highschooler H
  JOIN .... | has a friend
  WHERE ... | in SAME grade

EXCEPT

  SELECT H.id
  FROM Highschooler H
  JOIN .... | has a friend
  WHERE ... | in OTHER grade

キーワード「MINUS」を使用する SQL エンジンもあれば、「EXCEPT」を使用する SQL エンジンもあります。

ただし、UNION と同様に、これは両方のクエリを実行し、結果をフィルタリングすることに注意してください。これは、単一の do-it-all クエリとはパフォーマンスが異なる可能性がありますが、必ずしも悪いわけではないことに注意してください。多くの場合、特にソートされた単一の列に対する「例外」は非常に高速であるため、パフォーマンスが向上することさえあります

また、DB エンジンが許せば、ビューまたは CTE を使用して元のクエリを短縮しようとするかもしれませんが、美学を除いて、そうすることにはあまり意味がありません。

于 2013-02-10T16:16:27.280 に答える
0

一部のデータベースは、マイナス キーワードをサポートしています。

select whatever
from wherever
where id in
(select id
 from somewhere
 where something
 minus
 select id
 from somewhere
 where something else
 )

他のデータベースも同じ概念をサポートしていますが、マイナスの代わりにキーワード except を使用しています。

于 2013-02-10T16:14:04.977 に答える