如何防止INNER JOIN返回多个匹配?

时间:2012-03-16 21:12:39

标签: sql-server-2008 inner-join

左边表格中的每一行在右边的表格中只有一个匹配(右表是主表格,其中包含所有行;左表格只包含这些行的子集)。每个表中行的时间戳不完全匹配,但它们通常彼此相差1秒。因此,当我加入表格时,我必须使用:

FROM left_table INNER JOIN right_table
ON left_table.timestamp BETWEEN right_table.timestamp - .00015 AND right_table.timestamp + .00015
--This is approximately a 2 second wide range since this is a DATETIME field
AND left_table.name = right_table.name
AND ........

除时间戳外,其他所有条件都完全匹配。有办法解决这个问题吗?

大多数情况下,这足以仅返回1行,但有时当彼此之间存在两个相同的行时,它们都将被返回。

3 个答案:

答案 0 :(得分:2)

这应该更准确。现在获得欺骗的唯一方法是,他们都有相同的时差:

FROM left_table 
INNER JOIN 
  (
     SELECT l.name, min(abs(r.timestamp - l.timestamp)) as offset
     FROM left_table l
     INNER JOIN right_table ON r on r.name=l.name
     GROUP BY l.name
  ) lrmap ON left_table.name = lrmap.name
INNER JOIN right_table
ON left_table.name = right_table.name
    AND abs(left_table.timestamp-right_table.timestamp) = lrmap.offset
但是,我不会保证性能,因为减法很慢并且将它们放在abs()函数中会杀死在这些列上使用索引的任何机会。如果我有更多的时间花在一起,我可能会把一些更友好的索引放在一起...但也许不是,因为这看起来像弱表设计给我,真正的修复将是添加一个列更直接地链接记录。

答案 1 :(得分:1)

如果您只需要精确到秒,那么您可以在选择中截断其余部分。

答案 2 :(得分:0)

where exists()条款是防止笛卡尔积的好方法

FROM left_table lt
where exists(
    select 1 from right_table
    where lt.[timestamp] BETWEEN [timestamp] - .00015 AND [timestamp] + .00015
    and lt.name=name
    AND ........
)
AND ........