如何在表B中按日期对表A中的SQL Server行进行分组

时间:2012-08-08 22:38:34

标签: sql-server-2008

这在理论上很简单,但我很难弄明白。

我有两个SQL Server表:

  1. 购买日期和总数

    的购买清单
    select total, date from purchases
    
  2. 特定工作和旅行日期的行驶里程列表

    select travelDate, miles from trips
    
  3. 编辑:为了保留我的问题的答案/讨论,我正在重新阐述这一要求。

    我需要弄清楚每次购买之间的总里程数。

    我想要比整体平均值更准确。

    我可以通过在每个trips日期之间总结purchases的所有里程来手动获取此值。现在,我只想自动化这个过程。

    分组应该是所有trips日期大于purchases日期A且小于purchases日期B都是purchases日期A组的一部分。

1 个答案:

答案 0 :(得分:2)

固化我的密集度,我看到你的要求是合理的,将问题视为“替代燃料成本” - 使用下次加油的燃料成本而不是之前购买的成本实际使用的燃料(变得非常复杂,非常快)。卷然后无关紧要。试试这个尺寸。

SELECT
   T.*,
   P.*, -- from previous purchase
   N.*, -- from next purchase (NULL if none yet)
   TripCost = N.Total * T.Miles / M.MilesThisFill
FROM
   dbo.Trips T
   CROSS APPLY (
      SELECT TOP 1 *
      FROM dbo.Purchases P
      WHERE P.[Date] < T.travelDate
      ORDER BY P.[Date] DESC
   ) P
   CROSS APPLY (
      SELECT TOP 1 *
      FROM dbo.Purchases P
      WHERE P.[Date] > T.travelDate
      ORDER BY P.[Date]
   ) N
   CROSS APPLY (
      SELECT Sum(miles) MilesThisFill
      FROM dbo.Trips T2
      WHERE
         T2.[Date] > P.[Date]
         AND T2.[Date] < N.[Date]
   ) M;

或者这是一个版本,对问题的看法非常不同,但应该给出相同的结果。让我知道哪一个表现更好,是吗? (SET STATISTICS IO ON; SET STATISTICS TIME ON;

WITH PSeq AS (
   SELECT
      Seq = Row_Number() OVER (ORDER BY [Date]),
      *
   FROM dbo.Purchases
), Slices AS (
   SELECT
      FromDate = P.[Date],
      ToDate = N.[Date],
      N.Total
   FROM
      PSeq P
      INNER JOIN PSeq N
         ON P.Seq + 1 = N.Seq
), TotalMiles AS (
    SELECT
       S.FromDate,
       Sum(T.Miles) MilesThisFill
    FROM
      Slices S
      INNER JOIN dbo.Trips T
         ON T.travelDate BETWEEN S.FromDate AND S.ToDate
    GROUP BY
       S.FromDate 
)
SELECT
   T.travelDate,
   S.FromDate,
   S.ToDate,
   TripCost = S.Total * T.Miles / M.MilesThisFill
FROM
   Slices S
   INNER JOIN dbo.Trips T
      ON T.travelDate BETWEEN S.FromDate AND S.ToDate 
   INNER JOIN dbo.TotalMiles M
      ON S.FromDate = L.FromDate;

我提前为任何拼写错误或错误道歉...我还没有测试过代码。

只是为了笑,这是第一个被转换为一个甚至可以在SQL Server 2000上运行的版本的查询!

SELECT
   T.travelDate,
   T.Miles,
   T.ToDate,
   TripCost = P.Total * T.Miles / M.MilesThisFill
FROM
   (
      SELECT
         T.travelDate,
         T.Miles,
         ToDate = (
            SELECT TOP 1 P.Date
            FROM dbo.Purchases P
            WHERE P.[Date] > T.travelDate
            ORDER BY P.[Date]
         )
      FROM
         dbo.Trips T
   ) T
   INNER JOIN (
      SELECT
         ToDate = (
            SELECT TOP 1 P.Date
            FROM dbo.Purchases P
            WHERE P.[Date] > T2.travelDate
            ORDER BY P.[Date]
         ),
         MilesThisFill = Sum(T2.Miles)
      FROM dbo.Trips T2
      GROUP BY
         (
            SELECT TOP 1 P.Date
            FROM dbo.Purchases P
            WHERE P.[Date] > T2.travelDate
            ORDER BY P.[Date]
         )
   ) M ON T.ToDate = M.ToDate
   INNER JOIN dbo.Purchases P
      ON T.ToDate = P.[Date];

这实际上暴露了我可能不需要在我的第一个查询中查找上一个购买日期,如果我做对了...所以这是最终版本:

WITH TripData AS (
   SELECT
      T.Miles,
      T.travelDate,
      ToDate = (
         SELECT TOP 1 P.[Date]
         FROM dbo.Purchases P
         WHERE P.[Date] > T.travelDate
         ORDER BY P.[Date]
      )
   FROM
      dbo.Trips T
)
SELECT
   T.*,
   P.*,
   TripCost = P.Total * T.Miles / M.MilesThisFill
FROM
   TripData T
   INNER JOIN dbo.Purchases P
      ON T.ToDate = P.[Date]
   INNER JOIN (
      SELECT
         T2.ToDate,
         Sum(T2.Miles) MilesThisFill
      FROM TripData T2
      GROUP BY
         T2.ToDate
   ) M ON T.ToDate = M.ToDate;

注意:TripCost表达式的顺序很重要,因为Miles和TotalMiles是整数。如果将P.Total放在最后,则会得到错误的答案,因为Miles / TotalMiles将转换为整数。