我在SQL Server中工作时出现以下示例问题。 Brandon更喜欢PC和Mac,Sue更喜欢PC,而Alan更喜欢Mac。数据将表示如下。我不得不在这里做出一些妥协,但希望你能得到这样的结果:
表1:用户
uID (INT PK), uName (VARCHAR)
1 'Brandon'
2 'Sue'
3 'Alan'
表2:计算机
cID (INT PK), cName (VARCHAR)
1 'Mac'
2 'PC'
表3:UCPref - 存储每个用户的计算机首选项
uID (INT FK), cID (INT FK)
1 1
1 2
2 1
3 2
现在,如果我想选择喜欢PC的OR Mac的每个人都很容易。有十几种方法可以做到这一点,但是如果我有一个输入的项目列表,那么IN子句非常简单:
SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE cID IN (1,2)
我遇到的问题是,当我只想选择喜欢BOTH PC和Android的人时会发生什么?我可以在多个子查询中执行此操作,但这不是很可扩展。
SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE u.uID IN (SELECT uID FROM UCPref WHERE cID = 1)
AND u.uID IN (SELECT uID FROM UCPref WHERE cID = 2)
如何编写此查询,以便您可以返回喜欢多台计算机的用户,同时考虑到可能有数百甚至数千种不同类型的计算机(意味着没有子查询)?如果只有你可以修改IN子句以获得像'ALL'这样的关键词来表示你只想匹配括号中包含所有项目的那些记录?
SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE cID IN *ALL* (1,2)
答案 0 :(得分:0)
SELECT u.uname
FROM USERS u
JOIN UCPREF ucp ON ucp.uid = u.uid
JOIN COMPUTER mac ON mac.cid = ucp.cid
AND mac.cname = 'Mac'
JOIN COMPUTER pc ON pc.cid = ucp.cid
AND pc.cname = 'PC'
我正在使用表别名,因为我正在两次加入同一个表。
SELECT u.uname
FROM USERS u
JOIN UCPREF ucp ON ucp.uid = u.uid
WHERE EXISTS (SELECT NULL
FROM COMPUTER c
WHERE c.cid = ucp.cid
AND c.cid IN (1, 2)
GROUP BY c.cid
HAVING COUNT(*) = 2)
如果您要使用IN
子句,则必须使用GROUP BY/HAVING
,但COUNT()存在风险。有些db不允许超过*,而MySQL允许DISTINCT ...
。问题是,如果你不能在计数中使用DISTINCT
,你可以获得值2的两个实例,它对SQL有效 - 给你一个误报。