3

我们有许多预订,其中一项要求是我们根据其航段显示预订的最终目的地。我们的业务已将最终目的地定义为我们停留时间最长的目的地。起源是第一个出发点。

请注意,这不是行程时间最长的路段,即,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 将是最好的方法,但是到目前为止我的尝试都失败了。任何帮助将不胜感激。

我已经设法使以下查询正常工作,但由于顶部的原因,它一次只能工作一个,但我不知道如何调整它:

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 回答
3

您可以使用 OUTER APPLY + TOP 运算符来查找下一个值 SegNum。在找到段之间的间隙后,使用带有 OVER 子句的 MIN/MAX 聚合函数作为 CASE 表达式中的条件

;WITH cte AS
 (
  SELECT seg.BookingID,
         CASE WHEN MIN(seg.segNum) OVER(PARTITION BY seg.BookingID) = seg.segNum 
              THEN seg.DepartureCity END AS Origin,
         CASE WHEN MAX(DATEDIFF(MINUTE, seg.ArrivalDate, o.DepartDate)) OVER(PARTITION BY seg.BookingID) 
           = DATEDIFF(MINUTE, seg.ArrivalDate, o.DepartDate)
              THEN o.DepartureCity END AS Destination
  FROM Segments seg (NOLOCK)
    OUTER APPLY (
                 SELECT TOP 1 seg2.DepartDate, seg2.DepartureCity
                 FROM Segments seg2
                 WHERE seg.BookingID = seg2.BookingID 
                   AND seg.SegNum < seg2.SegNum
                 ORDER BY seg2.SegNum ASC
                 ) o
  )
  SELECT b.Locator, MAX(c.Origin) AS Origin, MAX(c.Destination) AS Destination
  FROM cte c JOIN Bookings b ON c.BookingID = b.BookingID
  GROUP BY b.Locator

见演示SQLFiddle

于 2013-07-15T13:47:32.360 回答
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. 从下面的屏幕截图中可以看出,有两条记录的秒差相同。如果你想同时显示它们(或者如果有的话全部显示),而不是ROW_NUMBER函数使用RANK函数。

  2. DATEDIFF的返回类型是 INT。因此,秒最大参考值是有限制的。如下:

如果返回值超出 int 的范围(-2,147,483,648 到 +2,147,483,647),则返回错误。对于毫秒,startdate 和 enddate 之间的最大差异是 24 天 20 小时 31 分钟和 23.647 秒。其次,最大差异是 68 岁。

于 2013-07-15T12:59:14.000 回答