【问题标题】:MySql self JOIN queryMySql 自联接查询
【发布时间】:2020-12-05 00:02:12
【问题描述】:

我有这张桌子

mysql> describe skill_usage;
+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| skill_id | int(11) | NO   | MUL | NULL    |       |
| job_id   | int(11) | NO   | MUL | NULL    |       |
+----------+---------+------+-----+---------+-------+

并且知道在我的数据中,有一个 job_id (6) 用于 skill_id 3 和 4:

mysql>  select * from skill_usage;
+----------+--------+
| skill_id | job_id |
+----------+--------+
|        1 |      1 |
|        2 |      2 |
|        3 |      3 |     <----  matches only one part of the AND clause
|        3 |      4 |     <----  matches only one part of the AND clause
|        2 |      5 |
|        3 |      6 |     <==== matches both parts of the AND clause
|        4 |      6 |     <====
|        2 |      7 |
+----------+--------+
8 rows in set (0.00 sec)

这是我尝试过的:

SELECT DISTINCT s1.job_id FROM skill_usage AS s1 
  INNER JOIN skill_usage AS s2 ON s1.job_id = s2.job_id
    WHERE s1.skill_id IN (3,4)
    AND   s2.skill_id IN (3,4)

我认为这意味着“查找所有与skill_id 3 和skill_id 4 匹配的job_id”。

显然不是:

mysql> SELECT DISTINCT s1.job_id FROM skill_usage AS s1
    ->   INNER JOIN skill_usage AS s2 ON s1.job_id = s2.job_id
    ->     WHERE s1.skill_id IN (3,4)
    ->     AND   s2.skill_id IN (3,4);
+--------+
| job_id |
+--------+
|      3 |
|      4 |
|      6 |
+--------+
3 rows in set (0.00 sec)

我做错了什么?我的查询应该如何阅读?我认为是时候读一本好书或 Udemy 课程了,但我自己的封面都没有。

我的查询正确找到 job_id = 6,但错误地 (IMO) 找到 job_id 3 和 4。我希望它们无法通过 AND 子句。

【问题讨论】:

标签: mysql


【解决方案1】:

你可以在这里使用聚合:

SELECT job_id
FROM skill_usage
WHERE skill_id IN (3, 4)
GROUP BY job_id
HAVING MIN(skill_id) <> MAX(skill_id);

此查询应受益于以下索引:

CREATE INDEX idx ON skill_usage (skill_id, job_id);

WHEREHAVING 子句在编写时都是sargable,并且应该能够利用这个索引。

【讨论】:

  • 谢谢,这行得通,但你能解释一下HAVING MIN(skill_id) &lt;&gt; MAX(skill_id)吗?那是在做什么?如果我搜索 skill_id 2 和 9999,它是否也能正常工作?
  • 想一想:如果我们只限制 两个技能,并且匹配的工作组有一个最小和最大的技能,这不是相同,那么它意味着这个作业有 3 和 4。注意:我们可以使用HAVING COUNT(DISTINCT skill_id) = 2,但是 MySQL 可能无法使用我建议的索引。
  • 感谢您的出色回答和澄清。在我问另一个问题之前,我会尝试自己弄清楚如何匹配 (skill_id = 3 AND 4) OR (skill_id = 5 AND 6)`。
  • 简单,简单!在WHERE 之后只是一个OR skill_id in (x,y)
  • 不...只是在having子句中添加更多逻辑。
【解决方案2】:

替代解决方案。
(参考db fiddle

select s1.job_id
  from skill_usage s1
  where s1.skill_id = 3
    and s1.job_id in (
                       select s2.job_id
                         from skill_usage s2
                        where s2.skill_id = 4
                     )

【讨论】:

  • 我授予这个答案,因为它似乎更容易结合起来构建复杂的查询。例如,“查找具有技能 ID 3 和 4 或技能 ID 1) 的 job_id”变为 select distinct s1.job_id from skill_usage s1 where s1.skill_id = 3 and s1.job_id in ( select s2.job_id from skill_usage s2 where s2.skill_id = 4 ) or s1.skill_id=1 参见小提琴dbfiddle.uk/…
猜你喜欢
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多