SQL在相关表中查找最近生效日期

时间:2017-09-15 06:25:09

标签: sql sql-server database join sql-server-2016

我将通过声明此问题类似于SQL Join on Nearest Less Than Date来解释这个问题,但那里的解决方案对我的问题不起作用。我需要根据最近的日期“过滤”表格的结果,而不是选择单个列。

我有三张桌子。主表包含以下形式的时间票据数据:

ticketId 
ticketNumber 
ticketDate
projectId 

辅助表跟踪项目每个每日故障单上资源的费率计划。它看起来像这样:

scheduleId
projectId
effectiveDate

还有第三个表与第二个表相关,实际上包含适用的费率。像这样:

scheduleId
straightTime
overTime

在projectId上加入前两个表(显然)复制项目费率表中每条记录的数据。如果我对项目1有3个费率表,那么票据记录会产生如下结果:

 ticketNumber  | ticketDate   | projectId   | effectiveDate  | scheduleId
 ------------- | ------------ | ----------- | -------------- | ----------
 1234          | 2016-06-18   | 25          | 2016-06-01     | 1
 1234          | 2016-06-18   | 25          | 2016-06-15     | 2
 1234          | 2016-06-18   | 25          | 2016-06-31     | 3

使用示例:

可以直接在我的结果中选择effectiveDate
  SELECT *
    ,  (SELECT TOP 1 t1.effectiveFrom 
        FROM         dbo.labourRateSchedule t1
        WHERE        t1.effectiveFrom <= t2.[date] and t1.projectId = t2.projectId
        ORDER BY     t1.effectiveFrom desc) as effectiveDate

  FROM dbo.timeTicket t2
  ORDER BY t.date

但是,我需要能够将dbo.labourRateSchedule的ID加入到第三个表中,以获得适用的实际费率。将t1.ID添加到SELECT语句不会使JOIN可以访问另一个相关表。

我一直在尝试在FROM语句中加入SELECT语句,但结果只会导致最后一个effectiveDate值而不是最接近适用的ticketDate的值。

我非常感谢你们的任何帮助!

3 个答案:

答案 0 :(得分:1)

您可以使用FROM将子查询移动到CROSS APPLY子句:

SELECT *
FROM dbo.timeTicket tt
CROSS APPLY
(
  SELECT TOP(1) *
  FROM dbo.labourRateSchedule lrs
  WHERE lrs.projectId = tt.projectId
    AND lrs.effectiveFrom <= tt.date
  ORDER BY lrs.effectiveFrom desc
) best_lrs
JOIN dbo.schedule s on s.schedule_id = best_lrs.schedule_id
ORDER BY tt.date

答案 1 :(得分:0)

你可以尝试这样的事情(你应该改变一些东西,因为你没有发布所有信息)。

 SELECT A.*, C.*
  FROM timeTicket A
  INNER JOIN  (SELECT * , ROW_NUMBER() OVER (PARTITION BY projectId ORDER BY effectiveFrom DESC) AS RN
                FROM labourRateSchedule) B ON A.projectId=B.projectId AND B.RN=1
  INNER JOIN YOUR3TABLE C ON B.SCHEDULEID=C.SCHEDULEID

答案 2 :(得分:0)

你可以通过CTE和Rank功能 -

来做到这一点
create table timeTicket  (ticketId  int,
ticketNumber int ,
ticketDate smalldatetime ,
projectId int )
go

create table labourRateSchedule 
(scheduleId int,
projectId int,
effectiveDate smalldatetime ) 
go

create table ApplicableRates
(scheduleId int,
straightTime smalldatetime ,
overTime smalldatetime) 
go

insert into timeTicket
select 1 , 1234   ,'2016-06-18' ,25   
go

insert into labourRateSchedule
select 1 , 25   ,'2016-06-01'   
union all select 2 , 25   ,'2016-06-15'  
union all select 3 , 25   ,'2016-06-30'  
go

insert into ApplicableRates    
select 1 , '2016-06-07'    ,'2016-06-07'   
union all select 2 ,  '2016-06-17'      ,'2016-06-17'  
union all select 3 ,   '2016-06-22'     ,'2016-06-25'           
go

  with cte 
  as (
  select t1.ticketNumber    ,t1.ticketDate  ,t1.projectId       ,t2.effectiveDate   ,t3.scheduleId  ,t3.straightTime    
  ,t3.overTime , rank() over (  partition by t1.ticketNumber order by abs     (DATEDIFF(day,t1.ticketDate, t2.effectiveDate) ) )  DyaDiff 
  from  timeTicket t1 join  labourRateSchedule t2
  on t1.projectId = t2.projectId
  join ApplicableRates t3
  on t2.scheduleId = t3.scheduleId)
  select * from cte where DyaDiff = 1