2017-08-03 103 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