我得到了这张桌子:
用户
|id |Name | country|
--------------
|1 | Ben | Japan |
|2 | Jo | Japan |
|3 | Sam | US |
邮件
|id | subject|
--------------
|1 | Good |
|2 | Bonus |
Ref_Users_Mails
|user_id | mail_id|
-------------------
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
我希望得到以下结果: 得到所有用户 来自一组国家 不是来自一组国家 收到了这封mailIds的邮件 并且没有收到与其他mailIds的邮件
例如: 所有来自日本而非美国的用户 收到邮件1但未收到邮件2。
==>结果应该只是'Jo',但我设法得到'Jo'和'Ben'(因为'Ben'也有邮件Id 1)
如何过滤'Ben',因为他也收到了邮件Id 2?
这是我的疑问:
SELECT * FROM Users
LEFT JOIN Ref_Users_Mails
ON Users.id = Ref_Users_Mails.user_id
WHERE ( trim(Users.country) IN ( 'Japan' ) )
AND ( trim(Users.country) NOT IN ( 'US' ) )
AND ( trim(Ref_Users_Mails.mail_id) NOT IN ( 2 ) )
ORDER BY Users.user_id;
结果:
|id |Name | country|
--------------
|1 | Ben | Japan |
|2 | Jo | Japan |
通缉结果:
|id |Name | country|
--------------
|2 | Jo | Japan |
答案 0 :(得分:0)
要从包含country =' Japan'的用户获取行,这就足够了:
SELECT u.id
, u.name
, u.country
FROM Users u
WHERE TRIM(u.country) IN ('Japan')
ORDER BY u.id
没有必要在u.country上添加另一个谓词。这不是必要的:
AND TRIM(u.country) NOT IN ('US')
因为如果WHERE子句中的条件为真,我们保证是真的。
从该查询返回的集合中,我们只希望收到邮件的用户1.如果我们保证(user_id,mail_id)
元组在Ref_Users_Mails
中是唯一的,我们可以使用连接操作来获取这一点。
JOIN Ref_Users_Mails r
ON r.user_id = u.id
AND r.mail_id = 1
如果我们还想排除已收到邮件2的用户,我们可以使用反连接模式。
LEFT
JOIN Ref_Users_Mails q
ON q.user_id = u.id
AND q.mail_id = 2
WHERE q.user_id IS NULL
所以,把所有这些放在一起:
SELECT u.id
, u.name
, u.country
FROM Users u
JOIN Ref_Users_Mails r
ON r.user_id = u.id
AND r.mail_id = 1
LEFT
JOIN Ref_Users_Mails q
ON q.user_id = u.id
AND q.mail_id = 2
WHERE q.id IS NULL
AND TRIM(u.country) IN ('Japan')
ORDER BY u.id
还有其他查询模式将返回等效结果。例如,我们可以使用EXISTS和NOT EXISTS谓词。
SELECT u.id
, u.name
, u.country
FROM Users u
WHERE TRIM(u.country) IN ('Japan')
AND EXISTS
( SELECT 1
FROM Ref_Users_Mails r
WHERE r.user_id = u.id
AND r.mail_id = 1
)
AND NOT EXISTS
( SELECT 1
FROM Ref_Users_Mails q
WHERE q.user_id = u.id
AND q.mail_id = 2
)
ORDER BY u.id
如果我们不在Ref_Users_Mails中保证(user_id, mail_id)
元组是唯一的