如何使用 "left self exclusion join" 找到审计 table 中最新修改的列值?
How can I find the column value that was modified latest from audit table using "left self exclusion join"?
我有以下 table 设计(它是 immutable,而且很糟糕):
Table 1: "ids": id1, id2。
将每个 id1 映射到 1 个或多个 id2 值。
Table2"audit":id2,时间戳,unique_id。
将每个 id2 映射到其更改的审计跟踪。 unique_id 保证在 table
中的每一行都是唯一的
目标:对于 id1 的每个不同值; select 一行;包含最近根据 table 2.
修改的任何单个 id2 值(在 table 1 中映射到 id1 的值中)
我已经尝试使用 this SO question 中概述的 "left self exclusion join" 方法,但不太清楚如何让它发挥作用。我的查询看起来像:
select i1.id1, a2.id2
from ids i1
right join audit a1 on i1.id2=a1.id2
left join ids i2 on i1.id1=i2.id1
left outer join audit a2 on i2.id2=a2.id2
where a1.timestamp < a2.timestamp
and a1.unique_id!=a2.unique_id
-- and a1.id2 is null
问题是,这 returns 零行,因为在查询中(不包括最后注释掉的行)none 行的 id2 为零,所以我猜我的外部连接有误。
我哪里错了?
示例数据库 fiddle 在这里:http://sqlfiddle.com/#!6/f5c45/4
CREATE TABLE ids (id1 int, id2 int)
CREATE TABLE audit (id2 int, timestamp int, unique_id int)
insert into ids values (1,11)
insert into ids values (1,12)
insert into ids values (2,23)
insert into audit values (11,101,10000)
insert into audit values (11,104,10001)
insert into audit values (12,102,10002)
insert into audit values (12,103,10003)
insert into audit values (23,101,10004)
此数据的预期结果集:
id1 id2 explanation
1 11 id2=11 last modified at 104, id2=12 at 103.
2 23 Only 1 row. That case tripped my query too.
澄清:我知道这个问题可以通过相关的子查询来解决,而无需使用左自排除连接。我对如何执行此操作不感兴趣,我对我的左自排除连接查询有什么问题感兴趣。
修改后的答案:SQL Fiddle
CREATE TABLE ids (id1 int, id2 int)
CREATE TABLE audit (id2 int, timestamp int, unique_id int)
insert into ids values (1,11)
insert into ids values (1,12)
insert into ids values (2,23)
insert into audit values (11,101,10000)
insert into audit values (11,104,10001)
insert into audit values (12,102,10002)
insert into audit values (12,103,10003)
insert into audit values (23,101,10004)
查询 1:
SELECT
audit1.*
FROM (
select data.id1 as data_id, audit.id2 as fk, audit.timestamp, audit.unique_id
from audit
INNER JOIN ids data ON audit.id2 = data.id2
) as audit1
LEFT OUTER JOIN (
select data.id1 as data_id, audit.id2 as fk, audit.timestamp, audit.unique_id
from audit
INNER JOIN ids data ON audit.id2 = data.id2
) AS audit2 ON audit1.data_id = audit2.data_id
AND audit1.timestamp < audit2.timestamp
AND audit1.unique_id <> audit2.unique_id
WHERE audit2.data_id is null
| data_id | fk | timestamp | unique_id |
|---------|----|-----------|-----------|
| 1 | 11 | 104 | 10001 |
| 2 | 23 | 101 | 10004 |
linked SO 问题中的自排外连接方法的工作方式是设置从一个 table 到自身的左外部连接,以便每一行不是该行你想要的至少有一个 link,而你想要的行没有。所以而不是
left outer join audit a2 on i2.id2=a2.id2
你需要
left outer join audit a2 on a1.id2=a2.id2 AND a1.timestamp < a2.timestamp
这意味着不是给定 ID 的最高时间戳的每一行都将 link 到至少一个其他 a2 行,但最高时间戳(您想要的)不会。然后使用 WHERE A2.id2 IS NULL 子句删除所有不需要的行。
请注意,随着具有相同 ID 的项目数量的增加,将创建(和忽略)更多的中间数据。五个项目有 4 行用于最低时间戳,3 行用于下一个,依此类推。大小为阶乘 (n - 1),可以很快变大。
我有以下 table 设计(它是 immutable,而且很糟糕):
Table 1: "ids": id1, id2。
将每个 id1 映射到 1 个或多个 id2 值。
Table2"audit":id2,时间戳,unique_id。
将每个 id2 映射到其更改的审计跟踪。 unique_id 保证在 table
中的每一行都是唯一的目标:对于 id1 的每个不同值; select 一行;包含最近根据 table 2.
修改的任何单个 id2 值(在 table 1 中映射到 id1 的值中)我已经尝试使用 this SO question 中概述的 "left self exclusion join" 方法,但不太清楚如何让它发挥作用。我的查询看起来像:
select i1.id1, a2.id2
from ids i1
right join audit a1 on i1.id2=a1.id2
left join ids i2 on i1.id1=i2.id1
left outer join audit a2 on i2.id2=a2.id2
where a1.timestamp < a2.timestamp
and a1.unique_id!=a2.unique_id
-- and a1.id2 is null
问题是,这 returns 零行,因为在查询中(不包括最后注释掉的行)none 行的 id2 为零,所以我猜我的外部连接有误。
我哪里错了?
示例数据库 fiddle 在这里:http://sqlfiddle.com/#!6/f5c45/4
CREATE TABLE ids (id1 int, id2 int)
CREATE TABLE audit (id2 int, timestamp int, unique_id int)
insert into ids values (1,11)
insert into ids values (1,12)
insert into ids values (2,23)
insert into audit values (11,101,10000)
insert into audit values (11,104,10001)
insert into audit values (12,102,10002)
insert into audit values (12,103,10003)
insert into audit values (23,101,10004)
此数据的预期结果集:
id1 id2 explanation
1 11 id2=11 last modified at 104, id2=12 at 103.
2 23 Only 1 row. That case tripped my query too.
澄清:我知道这个问题可以通过相关的子查询来解决,而无需使用左自排除连接。我对如何执行此操作不感兴趣,我对我的左自排除连接查询有什么问题感兴趣。
修改后的答案:SQL Fiddle
CREATE TABLE ids (id1 int, id2 int)
CREATE TABLE audit (id2 int, timestamp int, unique_id int)
insert into ids values (1,11)
insert into ids values (1,12)
insert into ids values (2,23)
insert into audit values (11,101,10000)
insert into audit values (11,104,10001)
insert into audit values (12,102,10002)
insert into audit values (12,103,10003)
insert into audit values (23,101,10004)
查询 1:
SELECT
audit1.*
FROM (
select data.id1 as data_id, audit.id2 as fk, audit.timestamp, audit.unique_id
from audit
INNER JOIN ids data ON audit.id2 = data.id2
) as audit1
LEFT OUTER JOIN (
select data.id1 as data_id, audit.id2 as fk, audit.timestamp, audit.unique_id
from audit
INNER JOIN ids data ON audit.id2 = data.id2
) AS audit2 ON audit1.data_id = audit2.data_id
AND audit1.timestamp < audit2.timestamp
AND audit1.unique_id <> audit2.unique_id
WHERE audit2.data_id is null
| data_id | fk | timestamp | unique_id |
|---------|----|-----------|-----------|
| 1 | 11 | 104 | 10001 |
| 2 | 23 | 101 | 10004 |
linked SO 问题中的自排外连接方法的工作方式是设置从一个 table 到自身的左外部连接,以便每一行不是该行你想要的至少有一个 link,而你想要的行没有。所以而不是
left outer join audit a2 on i2.id2=a2.id2
你需要
left outer join audit a2 on a1.id2=a2.id2 AND a1.timestamp < a2.timestamp
这意味着不是给定 ID 的最高时间戳的每一行都将 link 到至少一个其他 a2 行,但最高时间戳(您想要的)不会。然后使用 WHERE A2.id2 IS NULL 子句删除所有不需要的行。
请注意,随着具有相同 ID 的项目数量的增加,将创建(和忽略)更多的中间数据。五个项目有 4 行用于最低时间戳,3 行用于下一个,依此类推。大小为阶乘 (n - 1),可以很快变大。