条件SQL连接

时间:2014-10-30 02:22:52

标签: sql sql-server join

我有我想象的是一个基本的SQL问题,并希望得到一些帮助。我正在使用MSSQL。

我有两张桌子:

Table A                          Table B
----------------------------------------------
A.ID |A.Date|                 B.ID|B.Date|B.Number

A.ID是独一无二的;没有重复的行。 B.ID不是唯一的,因此连接该列上的表可能会导致返回多行。要获取正确的记录,必须加入两个列,但这也会产生不良结果。例如:

Table A                |         Table B
----------------------------------------------
1     |01-01-2014      |     1    |01-01-2014|25
2     |01-30-2014      |     1    |04-30-2013|40
3     |03-24-2014      |     1    |10-12-2018|12
4     |05-28-2014      |     2    |11-17-2013|55

期望的结果是连接两个列并返回单行。我遇到的问题是,如果我使用示例数据连接两个列相等,则只返回第一行。如果我将ID列设置为相等并使用< =,那么多行将返回ID 1,这是不希望的。我无法使用最大日期,因为某些字段包含将来不会返回记录的日期,直到两个日期字段相等。在示例数据中,期望的结果将返回数字25和55.所以基本上我需要加入相等的ID列并且日期字段相等但如果表B中没有相同的日期,则返回最新日期的编号,假设它不是未来的日期。

希望这是有道理的。提前致谢。

4 个答案:

答案 0 :(得分:1)

是的,这有点棘手但是应该这样做:

with equalvalues as (
select b.* from a
inner join b on a.ID=b.ID and a.adate=b.bdate
),
latestdates as (
select b.id, MAX(b.bdate) as maxbdate
from b
where b.bdate<=GETDATE()
group by b.ID
)
select number from equalvalues
union all
select b.number from b
inner join latestdates d on d.ID=b.ID and d.maxbdate=b.bdate
where b.ID not in (select ID from equalvalues)

答案 1 :(得分:0)

试试这个:

-- build sample data
create table #TableA(
    ID int,
    [Date] smalldatetime
)
create table #TableB(
    ID int,
    [Date] smalldatetime,
    number int
)

insert into #TableA
select 1, '1/1/2014' union all
select 2, '1/30/2014' union all
select 3, '3/24/2014' union all
select 4, '5/28/2014'

insert into #TableB
select 1, '1/1/2014', 25 union all
select 1, '4/30/2013', 40 union all
select 1, '10/12/2018', 12 union all
select 2, '11/17/2013', 55

-- start
;with cte(ID, [Date], Number, rn) as(
    select
        a.id,
        b.date,
        number,
        row_number() over(
            partition by a.id 
            order by
                case
                    when a.date = b.date then dateadd(d, 1, getdate())
                    else b.date
                end
            desc                
        )
    from #TableA a
    inner join #TableB b
        on b.id = a.id
    where
        a.date <= getdate()
        and b.date <= getdate()
)
select 
    id,
    date,
    number
from cte where rn = 1
-- end

-- drop temp tables
drop table #TableA
drop table #TableB

答案 2 :(得分:0)

我建议使用相关子查询或apply运算符。这是方法:

select a.*, b.*
from tablea a outer apply
     (select top 1 b.*
      from tableb b
      where b.id = a.id and
            b.date <= a.date
      order by b.date desc
     ) b;

答案 3 :(得分:0)

我目前没有可用的SQL Server实例,因此我将发布适用于PostgreSQL的语法;它应该翻译得相当好。我的目标是派生Table B的主键,然后使用主键选择行。它适用于您提供的示例数据。我不知道你有什么规则可以确定日期是否太远了,所以我输入了一个硬编码的日期,可以很容易地换成绑定变量。

with KB as (
  select id as id, max(dt) as dt
  from (
    select B.id, B.dt, B.num
    from B
      inner join A on A.id = B.id and A.dt = B.dt
    union
    select B.id, max(B.dt), B.num from B
      inner join A on A.id = B.id and A.dt != B.dt
    where B.dt < convert(datetime, '2014.10.313', 102)
    group by B.id, B.num
  ) subquery
  group by id
)
select B.id, B.dt, B.num
from B
  inner join KB on KB.id = B.id and X.dt = B.dt;

工作原理:

第一个内部查询只是盲目地抓住完全匹配。他们需要,所以为什么不呢?第二个内部查询获取所有不精确的匹配(ID相等但日期不相同)。一旦组合了相等和不相等的匹配组合,外部查询将为每个max选择最新日期(ID)。此时,每一行ID每行必须有一个日期,因此唯一要做的就是获得完全匹配的行。

我不知道解释计划是什么样的。 不应该是坏事,但我可能完全错了。