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