SQL 外连接时间替换空值

Posted

技术标签:

【中文标题】SQL 外连接时间替换空值【英文标题】:SQL Outer Join Time Replace Null Values 【发布时间】:2013-01-02 14:12:11 【问题描述】:

(SQL SERVER 2008) 我在多个表中添加了时间戳记录以加入主/基表。时间点有时等于基表,但有时不等于。

创建表格的代码:

create table base (time float);
create table table2 (time float, val2 char(1));
create table table3 (time float, val3 int);
insert into base values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
insert into table2 values (1, 'a'),(5, 'z'),(6, 'm'),(9, 'b');
insert into table3 values (1.5, 1),(5.3, 10),(5.5, 0),(8.1, 4);

结果集应该是基表中的每条记录和其他表中的“最新”值。以前,这些表在 Excel 中使用设置为 TRUE 的 Vlookup “连接”,这会从已排序的表中获取最接近的匹配项。

最终结果应如下所示:

time | val2 | val3
1  | a | NULL
2  | a | 1
3  | a | 1
4  | a | 1
5  | z | 1
6  | m | 0
7  | m | 0
8  | m | 0
9  | b | 4
10 | b | 4

如何使用 SQL 语句复制它?

由于只有大约 100 条记录在播放,因此我将在这里将可读性置于效率之上。

【问题讨论】:

table3 的时间 1.5 与 base 的时间有什么关系。 【参考方案1】:

也许最易读的是select 子句中的相关子查询:

我一般不喜欢select 中的select,但相关子查询确实模仿了 Excel vlookup 的行为。

Select
  b.time,
  (Select max(t2.val2) From table2 t2 Where b.time >= t2.time) As val2,
  (Select max(t3.val3) From table3 t3 Where b.time >= t3.time) As val3
From
  base b
Order By
  b.time;    

http://sqlfiddle.com/#!3/3545e/18

(感谢 Laurence 提供上述代码和 SQL Fiddle。)

使用max 要求值不递减。无论如何,以下版本都可以使用:

select
  b.time,
  (select top 1 t2.val2 from table2 t2 where b.time >= t2.time order by t2.time Desc) as val2,
  (select top 1 t3.val3 from table3 t3 where b.time >= t3.time order by t3.time Desc) as val3
from
  base b

http://sqlfiddle.com/#!6/a5148/5

【讨论】:

@劳伦斯。 . .非常感谢。在过去的 5 分钟里,我一直在尝试将该代码放入答案中。 不用担心,比我的更简洁,并且以更直接的方式扩展到更多表。 正确的版本是select top 1 t2.val . . . order by time desc @GordonLinoff 差不多,得到了它:select b.time, (select top 1 t2.val2 from table2 t2 where b.time >= t2.time order by t2.time desc) as val2, (select top 1 t3.val3 from table3 t3 where b.time >= t3.time order by t3.time desc) as val3 from base b 按 DESC 排序并修正第二张桌子 2 t3 上的错字【参考方案2】:

一般原则是使用外连接来确保即使第二个表中没有匹配项也能获得结果。然后,您可以使用不等式来限制超出的任何内容,并使用max 来选择剩余的最高值。

这对于大型表可能效率低下,因为您实际上是在执行 t2t3 的交叉连接。最好每个都做一个嵌套查询,然后加入结果:

-- Easier to read    
Select
  b.time,
  max(t2.val2) As val2,
  max(t3.val3) As val3
From
  base b
    left outer join
  table2 t2
    on b.time >= t2.time
    left outer join
  table3 t3
    on b.time >= t3.time
Group By
  b.time
Order By
  b.time;

-- Probably faster
Select
  n.time,
  n.val2,
  Max(t3.val3)
From (
    Select
      b.time,
      Max(t2.val2) As val2
    From
      base b
        left outer join
      table2 t2
         On b.time >= t2.time
    Group By
      b.time
    ) n
    Left Outer Join
  table3 t3
    On n.time >= t3.time
Group By
  n.time,
  n.val2
Order By
  n.time;

http://sqlfiddle.com/#!3/3545e/15

【讨论】:

我原来的示例表有点误导——我编辑了 SQL 表语句以使其更具挑战性。 Val2 和 Val3 并不总是随着时间的推移而增加,因此以这种方式使用的 MAX() 并不能捕捉到我想要的东西。我不想要所有以下值的 MAX 值。相反,我需要值表中具有最大 table2.time 的值

以上是关于SQL 外连接时间替换空值的主要内容,如果未能解决你的问题,请参考以下文章

左外连接和空值转换

左外连接和右外连接的区别

具有空值的完全外连接自身

oracle左外连接不显示右空值

SQL内连接与外连接的区别

SQL中的左连接与右连接,内连接有啥区别