2017-09-15 5 views
0

この問題はSQL Join on Nearest Less Than Dateと似ているが、私の問題では解決できないということを前に説明します。 1つの列を選択する代わりに、最も近い日付に基づいて「フィルタリング」されたテーブルの結果が必要です。SQL関連テーブルの中で最も有効な日付を見つけよう

私は3つのテーブルを持っています。メインテーブルには、以下の形式のタイムチケットデータが含まれています。

ticketId 
ticketNumber 
ticketDate 
projectId 

セカンダリテーブルでは、プロジェクトの毎日のチケットの料金スケジュールが追跡されます。

scheduleId 
projectId 
effectiveDate 

実際に該当するレートを含む2番目のテーブルもあります。このような何か:PROJECTID上の最初の2つのテーブルを結合

scheduleId 
straightTime 
overTime 

は(明らかに)プロジェクトの料金表内のすべてのレコードのデータを複製します。私はプロジェクト1のための3つのレートのスケジュールを持っている場合は、チケットの記録は次のようになる:

私の結果にeffectiveDateを選択
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を3番目のテーブルに追加して、適用される実際のレートを取得することができます。 SELECTステートメントにt1.IDを追加しても、JOINから別の関連テーブルにアクセスすることはできません。

私はFROMステートメントでSELECTステートメントにJOINしようとしましたが、その結果は適用可能なticketDateに最も近い値ではなく、最後のeffectiveDate値でのみ発生します。

私はこれについてどんな助けにも大変感謝します!

+1

をものにビットをクリアするために提供してください「第1、第2」の代わりにテーブル名を使用して、クエリを構造と比較することができます。 – Serg

答えて

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

これは美しく機能しました。ありがとうございました。 – user2170742

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 
0

あなたはCTEとランク機能によってこれを行うことができます -

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 
関連する問題