【问题标题】:Conditional SQL joins条件 SQL 连接
【发布时间】:2014-12-25 23:05:31
【问题描述】:

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

我有两张桌子:

表 A 表 B ---------------------------------------------- A.ID |A.日期| B.ID|B.Date|B.Number

A.ID 是唯一的;没有重复的行。 B.ID 不是唯一的,因此加入该列上的表可能会导致返回多行。要获取正确的记录,有必要加入两个列,但这也存在不希望的结果的问题。例如:

表 A |表 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 列设置为相等并使用

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

【问题讨论】:

  • 那么,结果如何?你得到了适合你的答案吗?
  • 我为这方面的大量延误道歉......它暂时搁置了一段时间。我最终使用带有 ROW OVER 的相关子查询来对结果进行分区,并且只获取所需的结果。

标签: sql sql-server join


【解决方案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)

【讨论】:

    【解决方案2】:

    我建议使用相关子查询或应用运算符。方法如下:

    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】:

      试试这个:

      -- 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
      

      【讨论】:

        【解决方案4】:

        目前我没有可用的 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 相等但日期不相等)。一旦组合了相等的集合和不相等的匹配集合,外部查询就会为每个 ID 选择最新的日期 (max)。此时,每一行都必须为每个ID 提供一个日期,所以剩下要做的就是获取完全匹配的行。

        我不知道这个解释计划是什么样的。 不应该很糟糕,但我可能完全错了。

        【讨论】:

          猜你喜欢
          • 2013-05-18
          • 2011-03-29
          • 2023-04-10
          • 2012-09-17
          • 2020-05-19
          • 2015-05-13
          相关资源
          最近更新 更多