假设我有2张桌子:
Person
+----------+---------+
| PersonID | Email |
+----------+---------+
| 1 | a@a.com |
| 2 | b@b.com |
+----------+---------+
还有
PersonType
+--------------+----------+-------+
| PersonTypeID | PersonID | pType |
+--------------+----------+-------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 2 | 2 |
+--------------+----------+-------+
我想获得Person
的行,其中pType
等于1,而PersonType
表中没有任何其他值。像这样
SELECT *
FROM Person P
INNER JOIN PersonType PT ON P.PersonID = PT.PersonID AND pType=1;
但是返回
+----------+---------+--------------+----------+-------+
| PersonID | Email | PersonTypeID | PersonID | pType |
+----------+---------+--------------+----------+-------+
| 1 | a@a.com | 1 | 1 | 1 |
| 2 | b@b.com | 2 | 2 | 1 |
+----------+---------+--------------+----------+-------+
我希望它仅返回PersonID=1
,因为PersonID=2
的{{1}}为1和2。
pType
有可能吗?我尝试使用+----------+---------+--------------+----------+-------+
| PersonID | Email | PersonTypeID | PersonID | pType |
+----------+---------+--------------+----------+-------+
| 1 | a@a.com | 1 | 1 | 1 |
+----------+---------+--------------+----------+-------+
等各种形式的联接,但似乎无法解决这个问题。
此外,除此以外,我想知道如何返回pType = 1 AND 2的行。
not IN
PersonID 2具有PType 1和2,因此我只想返回该Person。我也将如何做?谢谢。
编辑
使用Bohemian的答案,我想出了一些方法来解决为pType = 1 AND 2查找行的情况。
+----------+---------+--------------+----------+-------+
| PersonID | Email | PersonTypeID | PersonID | pType |
+----------+---------+--------------+----------+-------+
| 2 | b@b.com | 2 | 2 | 1 |
| 2 | b@b.com | 3 | 2 | 2 |
+----------+---------+--------------+----------+-------+
这似乎可行。在这种情况下,有谁能做得更好?
答案 0 :(得分:2)
将其他外部联接添加到其他类型,并过滤掉未匹配的子联接:
SELECT *
FROM Person P
JOIN PersonType PT ON P.PersonID = PT.PersonID AND PT.pType=1
LEFT JOIN PersonType PT2 ON P.PersonID = PT2.PersonID AND PT2.pType != 1
WHERE PT2.pType IS NULL —- this is only null when there are no hits for other types
您还可以使用更普通的不存在:
SELECT *
FROM Person P
JOIN PersonType PT ON P.PersonID = PT.PersonID AND PT.pType=1
WHERE NOT EXISTS (
SELECT * FROM PersonType PT2
WHERE P.PersonID = PT2.PersonID AND PT2.pType!=1)
但是它效率较低,因为它使用了相关子查询(尽管可以对其进行优化,但实践仍然很差)。
答案 1 :(得分:1)
如果您只想要人员而不是人员类型中的行,则可以使用exists
和not exists
:
select p.*
from person p
where exists (select 1
from persontype pt
where pt.personid = p.personid and
pt.ptype = 1
) and
not exists (select 1
from persontype pt
where pt.personid = p.personid and
pt.ptype <> 1
);
但是,更通用的解决方案将使用group by
和having
。仅输入1:
select pt.personid
from persontype pt
group by pt.personid
having sum(case when pt.type = 1 then 1 else 0 end) > 0 and
sum(case when pt.type <> 1 then 1 else 0 end) = 0;
对于类型1和2,没有其他类型:
select pt.personid
from persontype pt
group by pt.personid
having sum(case when pt.type = 1 then 1 else 0 end) > 0 and
sum(case when pt.type = 2 then 1 else 0 end) > 0 and
sum(case when pt.type not in (1, 2) then 1 else 0 end) = 0;
注意:其中第一个通常简化为:
select pt.personid
from persontype pt
group by pt.personid
having min(pt.type) = max(pt.type) and
min(pt.type) = 1;
答案 2 :(得分:1)
您可以尝试使用NOT EXISTS
代替LEFT JOIN
:
SELECT *
FROM Person p
JOIN PersonType pt ON p.PersonID = pt.PersonID
LEFT JOIN (
SELECT PersonID
FROM PersonType
WHERE
PType > 1
) v ON v.PersonID = p.PersonID
WHERE
pt.PType = 1
AND v.PersonID IS NULL