我的主表有以下结构:
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将获取所有已确认的值...但是未确认的内容是什么?
答案 0 :(得分:1)
您可以使用反连接模式。使用外部联接返回一个表中的所有行。外连接将返回第二个表中的匹配行,但也将返回第一个表中不具有匹配行的行。诀窍是WHERE
子句中的谓词(条件),它排除了匹配的行,只留下那些没有匹配的行。
根据您的查询,返回m
,v
,f1
和f2
中c
中找不到匹配行的所有行这样的事情:
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
中存在行,因此规范有点含糊不清。可以对f1
和f2
表使用外连接操作(在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)