[英]SQL Query for all pairs of elements that are only in different groups
I have a table called Survey with a Group Column and a Subject Column 我有一个名为Survey的表,其中包含一个Group Column和一个Subject Column
CREATE TABLE survey (
`group` INT NOT NULL,
`subject` VARCHAR(16) NOT NULL,
UNIQUE INDEX (`group`, `subject`)
);
INSERT INTO survey
VALUES
(1, 'sports'),
(1, 'history'),
(2, 'art'),
(2, 'music'),
(3, 'math'),
(3, 'sports'),
(3, 'science')
;
I am trying to figure out a query that will return all pairs of subjects that are not part of the same group. 我试图找出一个查询,它将返回不属于同一组的所有主题对。 So from my above example, I would like to see these pairs returned in a table:
所以从上面的例子中,我希望看到这些对在表中返回:
science - history
science - art
science - music
history - math
sports - art
sports - music
history - art
history - music
Thus, the query shouldn't return: 因此,查询不应返回:
sports - history
as an example since they are both in Group 1. 作为一个例子,因为他们都在第1组。
Thanks so much. 非常感谢。
SELECT s1.subject,
s2.subject
FROM survey s1
JOIN survey s2
ON s1.subject < s2.subject
GROUP BY s1.subject,
s2.subject
HAVING COUNT(CASE
WHEN s1.groupid = s2.groupid THEN 1
END) = 0
Sample table 样本表
create table Survey(groupid int, subject varchar(100))
insert into Survey select
1, 'sports' union all select
1, 'history' union all select
2, 'art' union all select
2, 'music' union all select
3, 'math' union all select
3, 'sports' union all select
3, 'science'
The ANSI-compliant query, which works for all mainstream RDBMS 符合ANSI标准的查询,适用于所有主流RDBMS
select a.subject, b.subject
from (select distinct subject from Survey) A
inner join (select distinct subject from Survey) B on B.subject > A.subject
left join Survey C on C.subject = A.subject
left join Survey D on D.subject = B.subject and D.groupid = C.groupid
where D.groupid is null
order by a.subject, b.subject
Here's a slightly different approach: 这是一个略有不同的方法:
SELECT *
FROM (SELECT DISTINCT subject FROM yourtable) AS T1
JOIN (SELECT DISTINCT subject FROM yourtable) AS T2
ON T1.subject < T2.subject
WHERE NOT EXISTS
(
SELECT *
FROM yourtable T3
JOIN yourtable T4
ON T3.id = T4.id
WHERE T1.subject = T3.subject
AND T2.subject = T4.subject
)
ORDER BY t1.subject, t2.subject;
The standard way would be to use MINUS
to get the complement of all pairs that are in the same group, but MySQL doesn't support MINUS
. 标准方法是使用
MINUS
来获得同一组中所有对的补充,但MySQL不支持MINUS
。 For MySQL, you can transform a MINUS
into a statement based on the NOT IN
operator and a sub-query: 对于MySQL,您可以将
MINUS
转换为基于NOT IN
运算符和子查询的语句:
SELECT s1.subject, s2.subject
FROM survey AS s1
JOIN survey AS s2
WHERE (s1.subject, s2.subject) NOT IN
(
SELECT s1.subject, s2.subject
FROM survey AS s1
JOIN survey AS s2
ON s1.group = s2.group
)
;
Note that this can produce duplicates. 请注意,这可能会产生重复。 If you don't want them, use
SELECT DISTINCT
. 如果您不想要它们,请使用
SELECT DISTINCT
。
With indices and the sample data, the extended query plan is: 使用索引和示例数据,扩展查询计划是:
\n+----+--------------------+-------+--------+---------------+-------+---------+--------------------+------+----------+---------------------------------------------++ ---- + -------------------- + ------- + -------- + ------ --------- ------- + + --------- + -------------------- + - ----- + ---------- + --------------------------------- ------------ +\n|
| id |
id | select_type |
select_type | table |
表| type |
类型| possible_keys |
possible_keys | key |
关键| key_len |
key_len | ref |
ref | rows |
行| filtered |
过滤| Extra |
额外的|\n+----+--------------------+-------+--------+---------------+-------+---------+--------------------+------+----------+---------------------------------------------+
+ ---- + -------------------- + ------- + -------- + ------ --------- ------- + + --------- + -------------------- + - ----- + ---------- + --------------------------------- ------------ +\n|
| 1 |
1 | PRIMARY |
主要| s1 |
s1 | index |
指数| NULL |
NULL | group |
小组| 54 |
54 | NULL |
NULL | 7 |
7 | 100.00 |
100.00 | Using index;
使用索引; Using temporary |
使用临时|\n|
| 1 |
1 | PRIMARY |
主要| s2 |
s2 | index |
指数| NULL |
NULL | group |
小组| 54 |
54 | NULL |
NULL | 7 |
7 | 100.00 |
100.00 | Using where;
用在哪里; Using index;
使用索引; Using join buffer |
使用连接缓冲区|\n|
| 2 |
2 | DEPENDENT SUBQUERY |
相关的子信息| s1 |
s1 | index |
指数| group |
小组| group |
小组| 54 |
54 | NULL |
NULL | 7 |
7 | 85.71 |
85.71 | Using where;
用在哪里; Using index |
使用索引|\n|
| 2 |
2 | DEPENDENT SUBQUERY |
相关的子信息| s2 |
s2 | eq_ref |
eq_ref | group |
小组| group |
小组| 54 |
54 | test.s1.group,func |
test.s1.group,func | 1 |
1 | 100.00 |
100.00 | Using where;
用在哪里; Using index |
使用索引|\n+----+--------------------+-------+--------+---------------+-------+---------+--------------------+------+----------+---------------------------------------------+
+ ---- + -------------------- + ------- + -------- + ------ --------- ------- + + --------- + -------------------- + - ----- + ---------- + --------------------------------- ------------ +\n
Select S1.Subject As LeftSubject
, S2.Subject As RightSubject
From SourceData As S1
Join SourceData As S2
On S2.subject > S1.subject
Left Join (
Select S1.groupid
, S1.subject As LeftSubject
, S2.subject As RightSubject
From SourceData As S1
Join SourceData As S2
On S2.groupid = S1.groupid
And S2.subject > S1.subject
) As Z
On Z.groupid = S1.groupid
And Z.LeftSubject = S1.subject
And Z.RightSubject = S2.subject
Where Z.groupid is null
Another variant using outis' tuple format: 使用outis'tuple格式的另一个变体:
Select S1.Subject As LeftSubject
, S2.Subject As RightSubject
From SourceData As S1
Join SourceData As S2
On S2.subject > S1.subject
Where (S1.groupid, S1.subject, S2.subject) Not In (
Select S1.groupid
, S1.subject
, S2.subject
From SourceData As S1
Join SourceData As S2
On S2.groupid = S1.groupid
Where S2.subject > S1.subject
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.