2017-08-03 50 views
0

我有三個表(Users,Items,UserItems),其中UserItems是用戶和項目之間的多對多關係。我需要的是一個查詢,獲取用戶沒有的所有項目。SQL Server查詢三個表之間不存在關係

我已經創建了這裏一些假數據的SQL小提琴例如:http://sqlfiddle.com/#!6/a6856/1

CREATE TABLE Users (userID INT, firstName NVARCHAR(50)) 
CREATE TABLE Items (itemID INT, itemName NVARCHAR(50)) 
CREATE TABLE UserItems (userID INT, itemID INT) 

INSERT INTO Users (userID, firstName) 
VALUES (1, 'Jack'), (2, 'Jill'), (3, 'John'), (4, 'Jane'); 

INSERT INTO Items (itemID, itemName) 
VALUES (1, 'Bucket'), (2, 'Water'), (3, 'Cast'); 

INSERT INTO UserItems (userID, itemID) 
VALUES (1, 1), (1, 2), (1, 3), (2, 3); 

預期的效果用戶和他們沒有什麼物品:

--------------------------------- 
| userID | firstName | itemName | 
|--------|-----------|----------| 
| 2  | Jill  | Bucket | 
| 2  | Jill  | Water | 
| 3  | John  | Bucket | 
| 3  | John  | Water | 
| 3  | John  | Cast  | 
| 4  | Jane  | Bucket | 
| 4  | Jane  | Water | 
| 4  | Jane  | Cast  | 
--------------------------------- 

注:傑克做不需要在結果中,因爲他擁有所有三項。

謝謝!

回答

1
SELECT u.userId, u.firstName, i.itemId, i.itemName 
    FROM users u CROSS JOIN items i 
    LEFT OUTER JOIN useritems ui 
    ON u.userID = ui.userId AND i.itemId = ui.itemId 
    WHERE ui.itemId IS NULL 
    ORDER BY 1, 3; 
+0

子查詢在性能方面往往代價很高。通常,聯接將比子查詢執行得更快。將它添加到「JOINS和SUBQUERIES」。這不是一個經驗法則,有時執行計劃將是等同的。 –

+0

這個和@Nolan的答案一樣好,但是我更喜歡這個,因爲它更乾淨。我並沒有注意到速度上的差異,但我聽到你有關「經驗法則」的消息。 – zabuuq

4
select * 
from Users as u inner join Items as i on 1=1 
where not exists(select 0 from UserItems as ui where ui.userID=u.userID and i.itemID=ui.itemID) 
order by userID,firstName,itemID 
 
+--------+-----------+--------+----------+ 
| userID | firstName | itemID | itemName | 
+--------+-----------+--------+----------+ 
| 2  | Jill  | 1  | Bucket | 
| 2  | Jill  | 2  | Water | 
| 3  | John  | 1  | Bucket | 
| 3  | John  | 2  | Water | 
| 3  | John  | 3  | Cast  | 
| 4  | Jane  | 1  | Bucket | 
| 4  | Jane  | 2  | Water | 
| 4  | Jane  | 3  | Cast  | 
+--------+-----------+--------+----------+ 
+0

完美工作,謝謝! – zabuuq

1

這看起來像一個良好的用例EXCEPT運算符。

SELECT  U.UserID, I.itemID 
FROM  Users U 
CROSS JOIN Items I -- Gets a set of all users and all items 
EXCEPT 
SELECT  UI.UserID, UI.ItemID 
FROM  UserItems UI -- Removes the items that a user has. 
+0

這可行,但它並沒有給我我想要的結果。我需要添加第二個選擇來獲取我需要的firstName和itemName。 – zabuuq

0

NOT EXISTS似乎是一個完美的結合在這裏

SELECT 
    usr.userID 
    , usr.firstName 
    , itm.itemName 
FROM 
    Users usr 
    , Items itm 
WHERE NOT EXISTS 
(
    SELECT * 
    FROM UserItems usrItm 
    WHERE 
     usrItm.itemID = itm.itemID 
     AND usrItm.userID = usr.userID 
) 
ORDER BY 
    usr.userID 
, itm.itemID 
+0

謝謝。儘管@nolan擊敗你的答案。 – zabuuq