【问题标题】:Join two tables based on column condtion根据列条件连接两个表
【发布时间】:2017-03-14 18:10:55
【问题描述】:

在 MS SQL Server 中,有两个表,“T1”和“T2”,有一个公共字段“ID (PK)”,其中 ID 是唯一的,但对于相同的 ID 记录,T1 和 T2 中的日期可能不同,ABC 或 DEF 的内容也可能不同 E.g:

----------
T1:
----------
ID   Date     A     B      C
----------
55   12/1/17  Jim  Smith  Male
77   12/2/17  Jim  Green  Male
99   10/3/17  Kate Lee    Male

T2:
----------
ID   Date       D    E     F
----------
55   12/1/17  Jim  Smith  Male
77   10/2/16  James  Jr   Male
99   12/25/17 Kathy  Lee  Male

我想要一个基于 ID 的某种形式的连接表,并根据最新日期选择 ABC 或 DEF,在这种情况下,我想要

----------
ID   Date     join1| join2 | join3
----------
55   12/1/17  Jim  Smith  Male
77   12/2/17  Jim  Green  Male
99   12/25/17 Kathy Lee   Male

这可能吗?

到目前为止,我想出的东西有点乏味:我首先做了一个完整的外部连接:

select * from T1 full outer join  T2 on T1.ID = T2.ID

具备以下条件:


ID   Date     A     B      C     Date2     D       E       F
----------
55   12/1/17  Jim  Smith  Male   12/1/17  Jim    Smith   Male
77   12/2/17  Jim  Green  Male   10/2/16  James   Jr     Male
99   10/3/17  Kate Lee    Male   12/25/17 Kathy   Lee    Male

然后我尝试使用case when then else选择ABC或DEF字段,看起来很丑,我担心性能。

select T1.ID, 
        case when T1.Date > T2.Date then T1.Date else T2.Date END as Date 
        case when T1.Date > T2.Date then T1.A else T2.D END as Join1
        case when T1.Date > T2.Date then T1.B else T2.E END as Joni2
        case when T1.Date > T2.Date then T1.C else T2.F END as Join3
from RESULT_TABLE

是否可以执行以下操作:

    select T1.ID,
           case when T1.Date > T2.Date then 
                T1.Date, T1.A as Join1, T1.B as Join2, T1.C as Join3
           else
                T2.Date, T2.D as Join1 , T2.E as Join2, T2.F as Join3
           END 
from RESULT_TABLE

【问题讨论】:

  • 虽然数据不应该影响 SQL - 你能提供更多数据吗? :)
  • 什么引擎(DB2、mySQL、SQL Server、Oracle)?我会使用 union、cte 和 row_number() over partition by... 来选择最近日期的记录的详细信息。
  • @xQbert 你能详细说明一下吗?顺便说一句,我正在使用 SQL Server。

标签: sql join


【解决方案1】:

一种方法使用case

select t1.id,
       (case when t1.date >= t2.date then t1.date else t2.date end) as date,
       (case when t1.date >= t2.date then t1.a else t2.a end) as a,
       (case when t1.date >= t2.date then t1.b else t2.a end) as b,
       (case when t1.date >= t2.date then t1.c else t2.a end) as c
from t1 join
     t2
     on t1.id = t2.id;

如果你不喜欢所有的case 表达式,你可以这样做:

select t1.*
from t1 join
     t2
     on t1.id = t2.id and t1.date >= t2.date
union all
select t2.*
from t1 join
     t2
     on t1.id = t2.id and t1.date < t2.date;

注意:您可能希望列出列而不是使用select *。此版本假定两个表具有完全相同的列、以相同的顺序、具有兼容的类型。

【讨论】:

  • 非常感谢!没想到回复这么快就回复了!我猜想用 union 的第二种解决方案不适合我的情况,因为除了 ID 和 Date 之外,我的表中的大多数字段都不同;所以我可能不得不使用“case when”。但是,我有大约 40 个字段需要“case when”,这与我在原始帖子中试图表达的内容非常相似——是否可以将“case when then else”分组?所以检查条件只需要做一次,而不是每个字段40次,如果没有,如果我使用这个查询创建一个视图会不会有任何性能问题?
【解决方案2】:

当然,

Select t1.Id, 
  case when t1.Date > t2.Date then t1.Date else t2.Date end date,
  case when t1.Date > t2.Date then t1.A else t2.D end AD,
  case when t1.Date > t2.Date then t1.B else t2.E end BE,
  case when t1.Date > t2.Date then t1.C else t2.F end CF

From T1 join T2 on t2.Id = t1.Id

【讨论】:

  • 如果我有很多像 ABC 或 DEF 这样的字段,比如 40 个字段,会不会对性能造成太大影响?有条件只能做一次吗?
  • 查询优化器应该会为您解决这个问题。使用显示计划查看。另外,一旦查询从磁盘读取行,它就在内存中,并且不必再次从磁盘重新读取。磁盘读取比内存访问贵 1000 倍,所以基本上不用担心。
猜你喜欢
  • 2016-11-18
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-30
  • 2020-10-01
  • 2015-10-09
  • 2021-01-14
相关资源
最近更新 更多