3

多数の予約があり、要件の 1 つは、セグメントに基づいて予約の最終目的地を表示することです。私たちのビジネスでは、最終目的地を、最も長く滞在する場所と定義しています。そしてOriginが最初の出発点。

これは移動時間が最長のセグメントではないことに注意してください。つまりDatediff(minute, DepartDate, ArrivalDate)、これはセグメント間のギャップが最長のセグメントを要求しています。

これはテーブルの簡易バージョンです。

Create Table Segments
(
  BookingID int,
  SegNum int,
  DepartureCity varchar(100),
  DepartDate datetime,
  ArrivalCity varchar(100),
  ArrivalDate datetime
);

Create Table Bookings
(
 BookingID int identity(1,1),
 Locator varchar(10)
);

Insert into Segments values (1,2,'BRU','2010-03-06 10:40','FIH','2010-03-06 20:20:00')
Insert into Segments values (1,4,'FIH','2010-03-13 21:50:00','BRU', '2010-03-14 07:25:00')
Insert into Segments values (2,2,'BOD','2010-02-10 06:50:00','AMS','2010-02-10 08:50:00')
Insert into Segments values (2,3,'AMS','2010-02-10 10:40:00','EBB','2010-02-10 20:40:00')
Insert into Segments values (2,4,'EBB','2010-02-28 22:55:00','AMS','2010-03-01 05:35:00')
Insert into Segments values (2,5,'AMS','2010-03-01 10:25:00','BOD','2010-03-01 12:15:00')
insert into Segments values (3,2,'BRU','2010-03-09 12:10:00','IAD','2010-03-09 14:46:00')
Insert into Segments Values  (3,3,'IAD','2010-03-13 17:57:00','BRU','2010-03-14 07:15:00')
insert into segments values (4,2,'BRU','2010-07-27','ADD','2010-07-28')
insert into segments values (4,4,'ADD','2010-07-28','LUN','2010-07-28')
insert into segments values (4,5,'LUN','2010-08-23','ADD','2010-08-23')
insert into segments values (4,6,'ADD','2010-08-23','BRU','2010-08-24')


Insert into Bookings values('5MVL7J')
Insert into Bookings values ('Y2IMXQ')
insert into bookings values ('YCBL5C')
Insert into bookings values ('X7THJ6')

ここで実際のデータを使用して SQL Fiddle を作成しました: SQL Fiddle Example

私は次のことを試みましたが、これは正しくないようです。

 SELECT Locator, fd.*
FROM Bookings ob
OUTER APPLY
(
SELECT Top 1 DepartureCity, ArrivalCity
from
(
SELECT DISTINCT
    seg.segnum ,
    seg.DepartureCity ,
    seg.DepartDate ,
    seg.ArrivalCity ,
    seg.ArrivalDate,
(SELECT
DISTINCT
    DATEDIFF(MINUTE , seg.ArrivalDate , s2.DepartDate)
FROM Segments s2
WHERE s2.BookingID = seg.BookingID AND s2.segnum = seg.segnum + 1) 'LengthOfStay'
    FROM Bookings b(NOLOCK)
    INNER JOIN Segments seg (NOLOCK) ON seg.bookingid = b.bookingid
    WHERE b.Locator = ob.locator
  ) a
Order by a.lengthofstay desc
  )
FD

私が期待する結果は次のとおりです。

Locator   Origin   Destination 

5MVL7J    BRU      FIH

Y2IMXQ    BOD      EBB

YCBL5C    BRU      IAD

X7THJ6    BRU      LUN

CTE が最良のアプローチであると感じていますが、これまでの私の試みは惨めに失敗しました。どんな助けでも大歓迎です。

次のクエリを機能させることができましたが、一番上のクエリのために一度に1つしか機能しませんが、微調整する方法がわかりません:

WITH CTE AS 
(
    SELECT distinct s.DepartureCity, s.DepartDate, s.ArrivalCity, s.ArrivalDate, b.Locator , ROW_NUMBER() OVER (PARTITION BY b.Locator ORDER BY SegNum ASC) RN 
    FROM Segments s
    JOIN bookings b ON s.bookingid = b.BookingID
)
SELECT C.Locator, c.DepartureCity, a.ArrivalCity
FROM 
(
SELECT TOP 1 C.Locator, c.ArrivalCity, c1.DepartureCity, DATEDIFF(MINUTE,c.ArrivalDate, c1.DepartDate) 'ddiff'
FROM CTE c
JOIN cte c1 ON c1.Locator = C.Locator AND c1.rn = c.rn + 1
ORDER BY ddiff DESC
) a
JOIN CTE c ON C.Locator = a.Locator
WHERE c.rn = 1
4

3 に答える 3

3

次のようなことを試すことができます:

;WITH CTE_Start AS 
(
    --Ordering of segments to eliminate gaps
    SELECT *, ROW_NUMBER() OVER (PARTITION BY BookingID ORDER BY SegNum) RN 
    FROM dbo.Segments  
)
, RCTE_Stay AS 
(
    --recursive CTE to calculate stay between segments
    SELECT *, 0 AS Stay FROM CTE_Start s WHERE RN = 1
    UNION ALL
    SELECT sNext.*, DATEDIFF(Mi, s.ArrivalDate, sNext.DepartDate) 
    FROM CTE_Start sNext
    INNER JOIN RCTE_Stay s ON s.RN + 1 = sNext.RN AND s.BookingID = sNext.BookingID
)
, CTE_Final AS
(
    --Search for max(stay) for each bookingID
    SELECT *, ROW_NUMBER() OVER (PARTITION BY BookingID ORDER BY Stay DESC) AS RN_Stay 
    FROM RCTE_Stay
)
--join Start and Final on RN=1 to find origin and departure
SELECT b.Locator, s.DepartureCity AS Origin, f.DepartureCity AS Destination
FROM CTE_Final f
INNER JOIN CTE_Start s ON f.BookingID = s.BookingID
INNER JOIN dbo.Bookings b ON b.BookingID = f.BookingID
WHERE s.RN = 1 AND f.RN_Stay = 1

SQLFiddle デモ

于 2013-07-15T12:06:14.693 に答える
0

以下の声明:

;WITH DataSource AS
(

  SELECT ROW_NUMBER() OVER(PARTITION BY BookingID ORDER BY DATEDIFF(SS,DepartDate,ArrivalDate) DESC) AS Row
        ,Segments.BookingID
        ,Segments.SegNum
        ,Segments.DepartureCity
        ,Segments.DepartDate
        ,Segments.ArrivalCity
        ,Segments.ArrivalDate
        ,DATEDIFF(SS,DepartDate,ArrivalDate) AS DiffInSeconds
  FROM Segments
)
SELECT * 
FROM DataSource DS
INNER JOIN Bookings B
  ON DS.[BookingID] = B.[BookingID]

次の出力が得られます。

ここに画像の説明を入力

したがって、上記のステートメントに次の句を追加します。

WHERE Row = 1

必要なものを与えてくれます。

いくつかの重要なこと:

  1. 以下のスクリーンショットからわかるように、秒の差が同じ 2 つのレコードがあります。両方 (または存在する場合はすべて) を表示する場合は、代わりにROW_NUMBER関数の代わりにRANK関数を使用します。

  2. DATEDIFFの戻り型は INT です。そのため、秒の最大遅延値には制限があります。それは次のとおりです。

戻り値が int の範囲外 (-2,147,483,648 ~ +2,147,483,647) の場合、エラーが返されます。ミリ秒の場合、開始日と終了日の最大差は 24 日 20 時間 31 分 23.647 秒です。第二に、最大の差は 68 年です。

于 2013-07-15T12:59:14.000 に答える