这个问题已经有几年了,但我是通过重复来的。我也想提出一个更通用的解决方案。如果您知道自己始终拥有固定数量的祖先,则可以使用答案中已经建议的一些自连接。如果您想要通用方法,请继续阅读。
你在这里需要的是关系代数中的商。商或多或少是笛卡尔积的反转(或 SQL 中的交叉连接)。
假设你的祖先集A 是(我在这里使用表格符号,我认为这样更便于理解)
ancestry
-----------
'England'
'France'
'Germany'
你的用户集U是
user_id
--------
1
2
3
那么笛卡尔积C=AxU是:
user_id | ancestry
---------+-----------
1 | 'England'
1 | 'France'
1 | 'Germany'
2 | 'England'
2 | 'France'
2 | 'Germany'
3 | 'England'
3 | 'France'
3 | 'Germany'
如果你计算集商U=C/A 那么你得到
user_id
--------
1
2
3
如果您重做笛卡尔积UXA,您将再次得到C。但请注意,对于一组T,(T/A)xA 不一定会重现T。例如,如果T 是
user_id | ancestry
---------+-----------
1 | 'England'
1 | 'France'
1 | 'Germany'
2 | 'England'
2 | 'France'
那么(T/A)就是
user_id
--------
1
(T/A)xA 将是
user_id | ancestry
---------+------------
1 | 'England'
1 | 'France'
1 | 'Germany'
请注意,user_id=2 的记录已被商和笛卡尔积运算消除。
您的问题是:哪个 user_id 在您的祖先集中拥有来自所有国家/地区的祖先?换句话说,您想要U=T/A,其中T 是您的原始集合(或您的桌子)。
要在 SQL 中实现商,您必须执行 4 个步骤:
- 创建您的祖先集的笛卡尔积和
所有用户 ID。
- 在笛卡尔积中查找原始集合中没有伙伴的所有记录(左连接)
- 从 2) 的结果集中提取 user_ids
- 从原始集合中返回所有未包含在 3) 的结果集中的 user_ids
让我们一步一步来。我将使用 TSQL 语法(Microsoft SQL 服务器),但它应该很容易适应其他 DBMS。作为表的名称(user_id, ancestry) 我选择ancestor
CREATE TABLE ancestry_set (ancestry nvarchar(25))
INSERT INTO ancestry_set (ancestry) VALUES ('England')
INSERT INTO ancestry_set (ancestry) VALUES ('France')
INSERT INTO ancestry_set (ancestry) VALUES ('Germany')
CREATE TABLE ancestor ([user_id] int, ancestry nvarchar(25))
INSERT INTO ancestor ([user_id],ancestry) VALUES (1,'England')
INSERT INTO ancestor ([user_id],ancestry) VALUES(1,'Ireland')
INSERT INTO ancestor ([user_id],ancestry) VALUES(2,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Germany')
INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Poland')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'England')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'Germany')
INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'France')
INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'Germany')
1) 创建您的祖先集和所有 user_id 集的笛卡尔积。
SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry
2) 查找笛卡尔积中在原始集合中没有伙伴的所有记录(左连接)和
3) 从 2) 的结果集中提取 user_ids
SELECT DISTINCT cp.[user_id]
FROM (SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry) cp
LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
WHERE a.[user_id] is null
4) 从原始集合中返回所有未包含在 3) 的结果集中的 user_id
SELECT DISTINCT [user_id]
FROM ancestor
WHERE [user_id] NOT IN (
SELECT DISTINCT cp.[user_id]
FROM (SELECT a.[user_id],s.ancestry
FROM ancestor a, ancestry_set s
GROUP BY a.[user_id],s.ancestry) cp
LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
WHERE a.[user_id] is null
)