4

このクエリがどのように機能するのか疑問に思っていました:

SELECT empname FROM Employee WHERE not exists (
    SELECT projid FROM Project WHERE not exists (
        SELECT empid, projid FROM Assigned WHERE empid = Employee.empid and projid = Project.projid
    )
)

すべてのプロジェクトに割り当てられているすべての従業員の名前を返すことになっており、機能しますが、正しく機能する方法/理由について混乱しています。

スキーマは次のとおりです。

Employee(empID INT,empName VARCHAR(100),job VARCHAR(100),deptID INT,salary INT);
割り当て済み (empID INT,projID INT,role VARCHAR(100));
Project(projID INT,title VARCHAR(100),budget INT,funds INT);

私はSQLが初めてなので、詳細/簡単な説明をいただければ幸いです。

4

2 に答える 2

4

何が起こっているのかを理解する必要があるときは、最も内側のクエリを探して、外側に向かって作業します。あなたの場合、始めましょう:

SELECT empid, projid 
FROM Assigned 
WHERE empid = Employee.empid and projid = Project.projid

これは、empidとprojidが前のテーブル(したがって、Employee.empidとProject.projid)にあるAssignedテーブルのすべてのレコードと一致します。

Projectsテーブルに5つのプロジェクトがあり、それぞれにEmployee1が割り当てられているとします。これにより、5つのレコードが返されます。また、Employee2がこれらのプロジェクトの1つに割り当てられていると仮定すると、1つのレコードが返されます。

次を見てください:

SELECT projid FROM Project WHERE not exists (
        ...
    )

これは、前のクエリ(5つのプロジェクトを持つEmployee1と1つのプロジェクトを持つEmployee2)で見つかったレコードについて、前のクエリから一致するものがない(存在しない)プロジェクトテーブルから任意のプロジェクトを選択することを示しています。つまり、Employee1はこのクエリからプロジェクトを返しませんが、Employee2は4つのプロジェクトを返します。

最後に、見てください

 SELECT empname FROM Employee WHERE not exists (
        ...
    )

2番目のクエリと同様に、前のクエリで見つかったレコード(これらの従業員をEmployee1などのすべてのプロジェクトと一致させるレコードがなく、従業員がEmployee2などのすべてのプロジェクトに割り当てられていない場合は一部のレコード)について、一致するものがない(ここでも存在しない)Employeeテーブル。つまり、前のクエリからプロジェクトが返されなかったため、Employee1が返され、前のクエリから1つ以上のプロジェクトが返されたため、Employee2は返されません。

お役に立てれば。EXISTSに関する追加情報は次のとおりです。

http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html

そしてその記事から:

すべての都市にどのような店がありますか?

SELECT DISTINCT store_type FROM stores s1   WHERE NOT EXISTS (
    SELECT * FROM cities WHERE NOT EXISTS (
      SELECT * FROM cities_stores
       WHERE cities_stores.city = cities.city AND cities_stores.store_type = stores.store_type));

最後の例は、二重にネストされたNOTEXISTSクエリです。つまり、NOTEXISTS句内にNOTEXISTS句があります。正式には、「店舗にない店舗がある都市は存在するか」という質問に答えます。しかし、ネストされたNOT EXISTSは、「すべてのyに対してxはTRUEですか?」という質問に答えると言う方が簡単です。</ p>

幸運を。

于 2013-02-01T04:50:08.007 に答える
1

NOT EXISTS (subquery)サブクエリの結果セットに行がない場合、述語はTRUEを返します。一致する行が見つかるとFALSEを返します。

本質的に、クエリは尋ねています

Employeeの各行について...Projectテーブルの各行をチェックして、Assignedテーブルに、Employee行のempidと一致するempidとinの行と一致するprojidを持つ行の行があるかどうかを確認します。プロジェクトテーブル。

Employeeからの行は、一致する行が見つからない場合にのみ返されます。

サブクエリのSELECTリストの式は重要ではないことに注意してください。チェックされているのは、そのサブクエリが1つ(または複数)の行を返すかどうかだけです。通常、SELECTリストではリテラル1を使用します。これは、チェックしているのは行が見つかったかどうかであることを思い出させてくれます。)

私は通常、次のようなスタイルでクエリを記述します。

SELECT e.empname 
  FROM Employee e 
 WHERE NOT EXISTS
       ( SELECT 1
           FROM Project p
          WHERE NOT EXISTS
                ( SELECT 1 
                    FROM Assigned a 
                   WHERE a.empid = e.empid
                     AND a.projid = p.projid
                )
       )

そして、私は「SELECT 1」を「1行を選択」と読みました)

そのクエリの結果セットは、基本的にこの(通常ははるかに効率の低い)クエリの結果セットと同等です。

SELECT e.empname
  FROM Employee e
 WHERE e.empid NOT IN
       ( SELECT a.empid
           FROM Assigned a
           JOIN Project p
             ON a.projid = p.projid
         WHERE a.empid IS NOT NULL
          GROUP
             BY a.empid
       )

そのNOT INサブクエリを実行して何かが返されることを確認できるため、クエリは少し理解しやすくなります。(NOT EXISTSサブクエリについて混乱する可能性があるのは、SELECTリストに返される式は重要ではないということです。重要なのは、行が返されるかどうかです。)NOTINにはいくつかの「落とし穴」があります。本当に悪いパフォーマンスに加えてサブクエリ。サブクエリがNULL値を返さないように注意する必要があります。そうすると、NOT IN(NULL、...)がtrueを返すことはないからです。

アンチジョインパターンを使用して、同等の結果セットを返すこともできます。

SELECT e.empname
  FROM Employee e
  LEFT
  JOIN ( SELECT a.empid
           FROM Assigned a
           JOIN Project p
             ON a.projid = p.projid
         WHERE a.empid IS NOT NULL
          GROUP
             BY a.empid
       ) o
    ON o.empid = e.empid
WHERE o.empid IS NULL

そのクエリでは、empidで「一致」を探しています。LEFTキーワードは、一致しない行(JOINの左側のテーブル)も返すようにMySQLに指示します。これらの行については、一致する行があった場合に返されるはずだった列の値の代わりにNULL値が返されます。「トリック」は、一致したすべての行を破棄することです。これを行うには、一致した場合はNULLではない列のNULLをチェックします。

NOT EXISTS述語を使用してこのクエリを作成する場合、実際には次のように作成することをお勧めします。

SELECT e.empname
  FROM Employee e
 WHERE NOT EXISTS
       ( SELECT 1
           FROM Assigned a
           JOIN Project p
             ON a.projid = p.projid
          WHERE a.empid = e.empid
       )
于 2013-02-01T04:52:02.510 に答える