【问题标题】:SQL Find Nearest Effective Date in Related TableSQL 在相关表中查找最近的生效日期
【发布时间】:2017-09-15 06:25:08
【问题描述】:

我会先说明这个问题与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

在我的结果中选择有效日期很简单:

  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 语句,但结果仅是最后一个有效日期值,而不是最接近适用的票证日期的值。

我将非常感谢任何帮助!

【问题讨论】:

  • 要清楚一点,请提供表名而不是“第一,第二”,以便可以将查询与结构进行比较。

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


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

【讨论】:

    【解决方案2】:

    您可以尝试这样的事情吗(您应该更改一些内容,因为您没有发布所有信息)。

     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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2012-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-23
        • 1970-01-01
        • 2016-03-04
        • 2019-05-31
        • 1970-01-01
        相关资源
        最近更新 更多