如何使用“左自排除连接”查找最近从审计表中修改的列值?

问题描述 投票:1回答:2

我有以下表格设计(它是不可变的,可怕的):

表1:“ids”:id1,id2。

将每个id1映射到1个或更多id2值。

表2“审计”:id2,时间戳,unique_id。

将每个id2映射到其更改的审计跟踪。 unique_id保证对表中的每一行都是唯一的

目标:对于id1的每个不同值;选择一行;包含任何单个id2值(在表1中映射到id1的那些值)最近根据表2进行了修改。

我曾尝试过在this SO question中概述的“左自我排除连接”方法,但无法弄清楚如何使其正常工作。我的查询看起来像:

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

问题是,这会返回零行,因为在查询中(不包括最后一个注释掉的行)没有一行没有id2,所以我猜我的外连接错了。

Where am I going wrong here?

示例DB小提琴在这里: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 tsql outer-join
2个回答
1
投票

修改回答: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

Results

| data_id | fk | timestamp | unique_id |
|---------|----|-----------|-----------|
|       1 | 11 |       104 |     10001 |
|       2 | 23 |       101 |     10004 |

0
投票

链接SO问题中自排除连接方法的工作方式是,您将左外连接从一个表设置为自身,这样每行不是您想要的行将至少有一个链接,而您想要的行才不是。而不是

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的最高时间戳的行将链接到至少一个其他a2行,但最高时间戳(您想要的那个)不会。然后使用WHERE A2.id2 IS NULL子句删除所有不想要的行。

请注意,随着您具有相同ID的项目数量的增加,创建(并忽略)更多中间数据。五个项目有4行用于最低时间戳,3行用于下一个时间戳等。大小是阶乘(n-1),可以快速变大。

© www.soinside.com 2019 - 2024. All rights reserved.