0

我正在使用 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 或 Mac 的每个人,那将非常容易。有十几种方法可以做到这一点,但如果我输入了一个项目列表,那么 IN 子句非常简单:

SELECT u.uName
FROM User u
INNER JOIN UCPref p ON u.uID = p.uID
WHERE cID IN (1,2)

我遇到的问题是,当我只想选择同时喜欢 PC 和 Mac 的人时会发生什么?我可以在多个子查询中做到这一点,但这不是很可扩展。

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)
4

1 回答 1

0

使用 JOIN:

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 有效 - 给您一个误报。

于 2009-11-18T01:30:04.200 回答