gpt4 book ai didi

sql - 如何在 SQL 中将顺序的、带时间戳的行组合在一起并返回每个组的日期范围

转载 作者:行者123 更新时间:2023-12-04 19:09:02 25 4
gpt4 key购买 nike

我有一个 MS SQL 2008 数据库表,如下所示:
Registration | Date | DriverID | TrailerID
一些数据的示例如下:

AB53EDH,2013/07/03 10:00,54,23
AB53EDH,2013/07/03 10:01,54,23
...
AB53EDH,2013/07/03 10:45,54,23
AB53EDH,2013/07/03 10:46,54,NULL <-- Trailer changed
AB53EDH,2013/07/03 10:47,54,NULL
...
AB53EDH,2013/07/03 11:05,54,NULL
AB53EDH,2013/07/03 11:06,54,102 <-- Trailer changed
AB53EDH,2013/07/03 11:07,54,102
...
AB53EDH,2013/07/03 12:32,54,102
AB53EDH,2013/07/03 12:33,72,102 <-- Driver changed
AB53EDH,2013/07/03 12:34,72,102

如您所见,数据表示在任何时间点哪个司机和哪个拖车被附加到哪个注册。我想要做的是生成一个报告,其中包含驱动程序和拖车的每个组合处于事件状态的时间段。因此,对于上面的示例数据,我想生成如下所示的内容:
Registration,StartDate,EndDate,DriverID,TrailerID
AB53EDH,2013/07/03 10:00,2013/07/03 10:45,54,23
AB53EDH,2013/07/03 10:46,2013/07/03 11:05,54,NULL
AB53EDH,2013/07/03 11:06,2013/07/03 12:32,54,102
AB53EDH,2013/07/03 12:33,2013/07/03 12:34,72,102

您将如何通过 SQL 执行此操作?

更新:感谢到目前为止的答案。不幸的是,当我将其应用于我拥有的生产数据时,它们停止工作。迄今为止提交的查询在应用于部分数据时无法正常工作。

下面是一些示例查询,用于生成数据表并使用上面的虚拟数据填充它。这里的数据比上例中的多:驱动程序、拖车组合 54,23 和 54,NULL 已被重复,以确保查询识别出这是两个不同的组。我还使用不同的日期范围复制了相同的数据三次,以测试在部分数据集上运行时查询是否有效:
CREATE TABLE [dbo].[TempTable](
[Registration] [nvarchar](50) NOT NULL,
[Date] [datetime] NOT NULL,
[DriverID] [int] NULL,
[TrailerID] [int] NULL
)

INSERT INTO dbo.TempTable
VALUES
('AB53EDH','2013/07/03 10:00', 54,23),
('AB53EDH','2013/07/03 10:01', 54,23),
('AB53EDH','2013/07/03 10:45', 54,23),
('AB53EDH','2013/07/03 10:46', 54,NULL),
('AB53EDH','2013/07/03 10:47', 54,NULL),
('AB53EDH','2013/07/03 11:05', 54,NULL),
('AB53EDH','2013/07/03 11:06', 54,102),
('AB53EDH','2013/07/03 11:07', 54,102),
('AB53EDH','2013/07/03 12:32', 54,102),
('AB53EDH','2013/07/03 12:33', 72,102),
('AB53EDH','2013/07/03 12:34', 72,102),
('AB53EDH','2013/07/03 13:00', 54,102),
('AB53EDH','2013/07/03 13:01', 54,102),
('AB53EDH','2013/07/03 13:02', 54,102),
('AB53EDH','2013/07/03 13:03', 54,102),
('AB53EDH','2013/07/03 13:04', 54,23),
('AB53EDH','2013/07/03 13:05', 54,23),
('AB53EDH','2013/07/03 13:06', 54,23),
('AB53EDH','2013/07/03 13:07', 54,NULL),
('AB53EDH','2013/07/03 13:08', 54,NULL),
('AB53EDH','2013/07/03 13:09', 54,NULL),
('AB53EDH','2013/07/03 13:10', 54,NULL),
('AB53EDH','2013/07/03 13:11', NULL,NULL)

INSERT INTO dbo.TempTable
SELECT Registration, DATEADD(M, -1, Date), DriverID, TrailerID
FROM dbo.TempTable
WHERE Date > '2013/07/01'

INSERT INTO dbo.TempTable
SELECT Registration, DATEADD(M, 1, Date), DriverID, TrailerID
FROM dbo.TempTable
WHERE Date > '2013/07/01'

最佳答案

此查询使用 CTE 来:

  • 创建按注册分组的有序记录集合
  • 对于每条记录,捕获上一条记录的数据
  • 比较当前和以前的数据以确定当前记录是否
    是司机/拖车分配的新实例
  • 仅获取新记录
  • 对于每条新记录,获取新司机/拖车前的最后日期
    分配发生

  • 链接到 SQL Fiddle

    代码如下:
    ;WITH c AS (
    -- Group records by Registration, assign row numbers in order of date
    SELECT
    ROW_NUMBER() OVER (
    PARTITION BY Registration
    ORDER BY Registration, [Date])
    AS Rn,
    Registration,
    [Date],
    DriverID,
    TrailerID
    FROM
    TempTable
    )
    ,c2 AS (
    -- Self join to table to get Driver and Trailer from previous record
    SELECT
    t1.Rn,
    t1.Registration,
    t1.[Date],
    t1.DriverID,
    t1.TrailerID,
    t2.DriverID AS PrevDriverID,
    t2.TrailerID AS PrevTrailerID
    FROM
    c t1
    LEFT OUTER JOIN
    c t2
    ON
    t1.Registration = t2.Registration
    AND
    t2.Rn = t1.Rn - 1
    )
    ,c3 AS (
    -- Use INTERSECT to determine if this record is new in sequence
    SELECT
    Rn,
    Registration,
    [Date],
    DriverID,
    TrailerID,
    CASE WHEN NOT EXISTS (
    SELECT DriverID, TrailerID
    INTERSECT
    SELECT PrevDriverID, PrevTrailerID)
    THEN 1
    ELSE 0
    END AS IsNew
    FROM c2
    )
    -- For all new records in sequence,
    -- get the last date logged before a new record appeared
    SELECT
    Registration,
    [Date] AS StartDate,
    COALESCE (
    (
    SELECT TOP 1 [Date]
    FROM c3
    WHERE Registration = t.Registration
    AND Rn < (
    SELECT TOP 1 Rn
    FROM c3
    WHERE Registration = t.Registration
    AND Rn > t.Rn
    AND IsNew = 1
    ORDER BY Rn )
    ORDER BY Rn DESC
    )
    , [Date]) AS EndDate,
    DriverID,
    TrailerID
    FROM
    c3 t
    WHERE
    IsNew = 1
    ORDER BY
    Registration,
    StartDate

    关于sql - 如何在 SQL 中将顺序的、带时间戳的行组合在一起并返回每个组的日期范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17448813/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com