我有一个表 P,其中包含 personid 列和 licensetypeid 列。
每个人都可以拥有多种许可证类型,为该人 ID 向表中添加额外的行。
我需要找到 personid 的 licenseid 为 1 和 5 的行。
我不能写:
SELECT personid, licensetypeid
FROM P
WHERE licensetypeid=1 AND licensetypeid=5;
我听说我应该使用自加入来执行此操作。如何进行自我加入以解决此问题?
自联接和其他多次访问表的技术将起作用,但如果您需要泛化到更大的 id 集,可能会降低性能并且不实用。
您可以通过计算每个人的匹配行数来对表进行一次引用:
select personid from P
where licensetypeid in ('1','5')
group by personid
having count(*) = 2
如果您需要更大的 licensetypeid 值,这可以很容易地扩展:
select personid from P
where licensetypeid in ('1','5','7')
group by personid
having count(*) = 3
(在自联接版本中,您必须为每个附加值添加一个附加联接)
或者,如果您想在更大的一组类型中找到至少具有 2 种类型的人:
select personid from P
where licensetypeid in ('1','5', '7', '10')
group by personid
having count(*) >= 2
现在,与您的示例查询不同,licensetypeid 不包含在结果集中。如果出于某种原因有必要这样做,您可以在 2 个值的情况下做一个简单的技巧:
select personid, min(licensetypeid) licensetype1, max(licensetypeid) licensetype2
from P
where licensetypeid in ('1','5')
group by personid
having count(*) = 2
但更通用的方法是将值分组到一个简单的集合中:
select personid, collect(licensetypeid) licensetypeidlist
from P
where licensetypeid in ('1','5')
group by personid
having count(*) = 2
select personid, licensetypeid
from P P1
where exists (
select 1
from P P2
where P2.personid = P1.personid
and P2.licensetypeid = 1
) and exists (
select 1
from P P2
where P2.personid = P1.personid
and P2.licensetypeid = 5
)
SELECT distinct
p1.personid
,p1.licensetypeid
,p2.licensetypeid
from P p1, P p2
WHERE p1.personid = p2.personid
AND p1.licensetypeid = 1
AND p2.licensetypeid = 5
;
尝试这个
select personid,licensetypeid from P where licensetypeid in ('1','5')
如果您的所需许可证类型集是“固定的”,或者至少如果所需许可证类型集的基数是固定的,那么给定的答案将可以正常工作。
否则,您需要编写与所谓的“关系除法”等效的 SQL。
情况如下:
(1) 计算至少缺少一种所需许可证类型的人员集:
SELECT personid
from P
WHERE EXISTS
(
SELECT licenseid
from NEEDEDLICENSETYPE AS NLT
WHERE NOT EXISTS (
SELECT *
FROM P AS PBIS
WHERE
PBIS.personid = P.personid AND
PBIS.licensetype = NLT.licensetype
)
)
NEEDELICENSETYPE 表示在特定调用中计算所需许可证类型集所需的任何 SQL 语句。
(2) 选择 (1) 中没有出现数字的人的数据:
SELECT ... FROM P WHERE personid NOT IN (...)