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

SQL Find Nearest Effective Date in Related Table

我会先说明这个问题与 SQL Join on Nearest Less Than Date 类似,但那里的解决方案不适用于我的问题。我不需要选择单个列,而是需要 table 的结果,即基于最近日期的 'filtered'。

我有三个 table。主要 table 包含以下形式的时间票数据:

ticketId 
ticketNumber 
ticketDate
projectId 

辅助 table 跟踪项目每张每日票证上的资源费率表。它看起来像这样:

scheduleId
projectId
effectiveDate

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

scheduleId
straightTime
overTime

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

 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

在我的结果中选择有效日期很简单,示例如下:

  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 加入第三个 table 以获得适用的实际费率。将 t1.ID 添加到 SELECT 语句不会使其可访问到另一个相关的 table.

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

我将不胜感激任何帮助!

你能试试这样吗(你应该改变一些东西,因为你没有 post 所有信息)。

 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

你可以通过 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

您可以使用 CROSS APPLY:

将子查询移动到 FROM 子句
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