内部联接不在哪里

时间:2016-01-26 13:41:32

标签: mysql

我的主表有以下结构:

id | created_at          | f1_id | f2_id
1    2016-01-23 11:41:21   5       7
2    2016-01-23 12:31:22   5       7

然后我有一张表1:n到上一张表:

main_id | value
1         aaa
1         bbb
2         ccc

然后我将1:1的表格与之前的表格进行确认:

f1_id | f2_id | value | confirmed_at
5       7       aaa     2016-01-25 21:41:51
9       9       ccc     2016-01-25 23:51:45

现在我想从主表的日期范围中获取所有未确认的值。如何在主表的范围内找到所有未确认的值?

f1和f2是主表中使用的1:1表和确认值。

SELECT *
FROM maintable m
INNER JOIN f1table f1 ON m.f1_id = f1.id
INNER JOIN f2table f2 ON m.f2_id = f2.id
INNER JOIN values v ON m.id = v.main_id
INNER JOIN confirmed c ON (v.value = c.value AND c.f1_id = m.f1_id AND c.f2_id = m.f2_id)
WHERE m.created_at BETWEEN '2016-01-20' AND '2016-01-24';

此SQL将获取所有已确认的值...但是未确认的内容是什么?

2 个答案:

答案 0 :(得分:1)

您可以使用反连接模式。使用外部联接返回一个表中的所有行。外连接将返回第二个表中的匹配行,但也将返回第一个表中具有匹配行的行。诀窍是WHERE子句中的谓词(条件),它排除了匹配的行,只留下那些没有匹配的行。

根据您的查询,返回mvf1f2c中找不到匹配行的所有行这样的事情:

SELECT m.id
     , m.created_at
     , m.f1_id
     , m.f2_id
     , v.main_id
     , v.value
  FROM maintable m
  JOIN f1table f1 ON m.f1_id = f1.id
  JOIN f2table f2 ON m.f2_id = f2.id
  JOIN values v ON m.id = v.main_id

  LEFT
  JOIN confirmed c
    ON c.value = v.value
   AND c.f1_id = m.f1_id
   AND c.f2_id = m.f2_id
 WHERE c.f1_id IS NULL

   AND m.created_at BETWEEN '2016-01-20' AND '2016-01-24'

来自c的“匹配”的任何行将在连接条件中评估的列具有非NULL值(即c.f1_id中的NULL值不会满足相等性比较。)因此,我们可以测试该列中的非NULL值,以确定哪些行匹配。

f1中不存在匹配的行时,您是否希望f2和/或confirmed中存在行,因此规范有点含糊不清。可以对f1f2表使用外连接操作(在LEFT之前添加JOIN关键字。)

反连接模式在一个不太复杂的示例中更容易理解。返回a

中不存在匹配行的b
SELECT a.foo
  FROM a
  LEFT
  JOIN b
    ON b.foo = a.foo
 WHERE b.foo IS NULL

答案 1 :(得分:0)

尝试使用confirmed where-clause将INNER JOIN替换为NOT EXISTS表。如下所示:

SELECT *
FROM maintable m
INNER JOIN f1table f1 ON m.f1_id = f1.id
INNER JOIN f2table f2 ON m.f2_id = f2.id
INNER JOIN values v ON m.id = v.main_id
WHERE m.created_at BETWEEN '2016-01-20' AND '2016-01-24'
AND NOT EXISTS (SELECT * FROM confirmed c WHERE v.value = c.value AND c.f1_id = m.f1_id AND c.f2_id = m.f2_id)