我遇到一个查询是,
SELECT it1.survey_set_id, it1.type, it1.value FROM survey_condition_filter it1 LEFT JOIN survey_condition_filter it2 ON(it1.survey_set_id = it2.survey_set_id AND it2.type = 3002) WHERE it1.type IN (2000, 2001, 2002) AND it2.value IS NULL;
为什么在上面的查询中使用self left-join。
SELECT survey_set_id, type, value FROM survey_condition_filter WHERE type IN (2000, 2001, 2002);
上面的查询不等同于第一个使用自左连接的查询。因为查询也只是过滤
IN (2000, 2001, 2002) AND it2.value IS NULL
。我对这里连接查询的使用感到困惑,无法真正理解第一个查询的工作原理。
这是表格survey_condition_filter
+---------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| survey_id | bigint | NO | PRI | NULL | |
| survey_set_id | bigint | NO | PRI | NULL | |
| type | int | NO | PRI | NULL | |
| condition | tinyint | NO | PRI | NULL | |
| value | varchar(15) | NO | PRI | NULL | |
| display_value | text | NO | | NULL | |
| order | int | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| created_by | varchar(255) | YES | | NULL | |
| updated_at | datetime | NO | | NULL | |
| updated_by | varchar(255) | YES | | NULL | |
| deleted_at | datetime | YES | | NULL | |
| deleted_by | varchar(255) | YES | | NULL | |
+---------------+--------------+------+-----+---------+-------+
这是一个反加入。我们外连接一个表,但只保留外连接的行(通过在这里应用
WHERE ... it2.value IS NULL
)。使用直截了当的NOT EXISTS
(或在许多情况下为NOT IN
)更常见——在我看来也更具可读性。
SELECT it1.survey_set_id, it1.type, it1.value
FROM survey_condition_filter it1
WHERE it1.type IN (2000, 2001, 2002)
AND NOT EXISTS
(
SELECT null
FROM survey_condition_filter it2
WHERE it2.survey_set_id = it1.survey_set_id
AND it2.type = 3002
);
此查询的作用很明显:选择所有类型为 2000/2001/2002 的行,其中不存在相同的 survey_set_id 的 3002 行。
如果 survey_set_id 是不可为 null 的列,您可以使用
NOT IN
,这会使查询更短:
SELECT it1.survey_set_id, it1.type, it1.value
FROM survey_condition_filter it1
WHERE it1.type IN (2000, 2001, 2002)
AND itl.survey_set_id NOT IN
(
SELECT it2.survey_set_id
FROM survey_condition_filter it2
WHERE it2.type = 3002
);