仅在IN(值)和NOT IN(其他值)时选择关联的id

时间:2013-01-30 00:16:36

标签: sql select

对于糟糕的标题抱歉,我想不出更好的方式来描述我的问题,所以我通过举例解释它来弥补它。

设置

如果你想跟随,那么这是为我的问题创建表格的SQL:

CREATE TABLE `student_sections` (`student_id` int(11) NOT NULL, `section_id` int(11) NOT NULL);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (1,11);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (1,12);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (1,13);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (1,14);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (1,15);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,12);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,13);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,14);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,21);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,22);
INSERT INTO `student_sections` (`student_id`,`section_id`) VALUES (2,23);

这导致下表:

| student_sections        |
|-------------------------|
| student_id | section_id |
|------------|------------|
| 1          | 11         |
| 1          | 12         |
| 1          | 13         |
| 1          | 14         |
| 1          | 15         |
| 2          | 12         |
| 2          | 13         |
| 2          | 14         |
| 2          | 21         |
| 2          | 22         |
| 2          | 23         |

方案

我有一个“小组”的部分,我必须找到所有与部分组合相关的学生。我的应用程序将有几个章节组。

section_id的“第1组”:(11,12,13,14,15) 学生1与所有部分(11,12,13,14,15)相关联。 学生2与(12,13,14)相关但不与(11,15)相关联。

section_id的“第2组”:(21,22,23,24,25) 学生2与(21,22,23)有关,但与(24,25)无关。

给定section_id(12,13,14)我需要选择与section_id相关联的student_id,而不是section_id的(11,15)。

例如,如果给定section_id(12,13,14),我想选择student_id(2)。即使student_id 1与section_id(12,13,14)相关联,她也与11和15相关联,所以我不希望她的id返回。

此查询的更高目的是我将其用作子查询来选择给定组合部分的学生列表。

另外,例如,如果给定section_id(12,13),则不会返回任何结果。

我尝试了什么

我尝试使用IN和NOT IN的混合,但因为5行有student_id 1和3行与(12,13,14)相关联,以下查询中的DISTINT()返回student_id 1和2。

SELECT
    DISTINCT(student_id)
FROM
    student_sections
WHERE
    section_id IN (12,13,14)
    AND section_id NOT IN (11,15)

2月1日更新

我添加了一些额外的用例数据,略微改变了查询的要求。学生将被安排在几个部门的“小组”中。

4 个答案:

答案 0 :(得分:3)

对于此类查询,我建议使用having子句进行聚合:

select ss.student_id
from student_sections ss
group by ss.student_id
having max(case when section_id = 12 then 1 else 0 end) = 1 and
       max(case when section_id = 13 then 1 else 0 end) = 1 and
       max(case when section_id = 14 then 1 else 0 end) = 1 and
       max(case when section_id not in (12, 13, 14) then 1 else 0 end) = 0

这是同一个想法的一个更简单的版本:

select ss.student_id
from student_sections ss
group by ss.student_id
having count(distinct section_id) = 3 and
       count(distinct case when section_id in (12, 13, 14) then section_id end) = 3

我喜欢第一个版本,因为它概括了很多“群内群体”问题。

答案 1 :(得分:1)

您需要选择两个选项:

SELECT student_id FROM student_sections
WHERE section_id IN (12,13,14)
   INTERSECT
SELECT student_id WHERE
   section_id NOT IN (11,15)

答案 2 :(得分:0)

SELECT student_id
     , COUNT(*) x
     , COUNT(CASE WHEN section_id IN(12,13,14) THEN 'foo' END) y
  FROM student_sections 
 GROUP 
    BY student_id;

答案 3 :(得分:0)

这是另一种选择,但我喜欢@ Gordon的回答:

SELECT ss.student_id
FROM student_sections ss
     left join (select student_id 
                  from student_sections 
                  where section_id NOT IN (12,13,14)
                  ) s on ss.student_id = s.student_id
WHERE s.student_id is null
GROUP BY ss.student_id
HAVING Count(distinct ss.section_id) = 3

Fiddle

或使用NOT EXISTS:

SELECT ss.student_id
FROM student_sections ss
WHERE NOT EXISTS (
  select null
  from student_sections 
  where section_id NOT IN (12,13,14)
    and student_id = ss.student_id
  )
GROUP BY ss.student_id
HAVING Count(distinct ss.section_id) = 3
祝你好运。