【问题标题】:Modify records to account for correct priority and order between two systems修改记录以说明两个系统之间的正确优先级和顺序
【发布时间】:2015-06-10 00:32:53
【问题描述】:

我有两个表来跟踪不同系统中的项目,为简单起见,我们称它们为 Alpha 和 Beta 系统。我正在尝试将这两个表合并为一个可以正确跟踪项目位置的表。

跟踪的项目从 Alpha 开始,可以进入 Beta。但是,由于系统未连接,因此输入 Beta 的开始时间并不总是与 Alpha 的结束时间匹配。

正确跟踪的示例项目如下

System---ID----Item------- Start---------------- End Alpha - 987 - 123 - 20/5/2015 07:00:00 - 20/5/2015 08:00:00 Alpha - 374 - 123 - 20/5/2015 08:00:00 - 20/5/2015 09:00:00 Beta - 184 - 123 - 20/5/2015 09:00:00 - 20/5/2015 10:00:00 Beta - 798 - 123 - 20/5/2015 10:00:00 - 20/5/2015 12:00:00

我的问题是因为系统没有链接,我有一些项目同时出现在 Alpha 和 Beta 中的情况。如下

System---ID----Item------- Start---------------- End Alpha - 987 - 123 - 20/5/2015 07:00:00 - 20/5/2015 08:00:00 Beta - 184 - 123 - 20/5/2015 07:30:00 - 20/5/2015 10:00:00 Alpha - 374 - 123 - 20/5/2015 08:00:00 - 20/5/2015 09:00:00 Beta - 798 - 123 - 20/5/2015 10:00:00 - 20/5/2015 12:00:00

Alpha 是更好的系统,应该始终受到信任。

所以在上述情况下我想要的结果是修改记录 184 并将它的开始时间更改为记录 374 的结束时间。

还有另一种情况也需要考虑,那就是 Alpha 记录在最后一个 Beta 记录开始之前开始和结束的地方。

有意义吗?我希望如此,过去几天我一直在发疯。

感谢您提供的任何帮助。

【问题讨论】:

  • 您要构建视图还是新的合并表?如果 Alpha 记录在最后一个 Beta 记录开始之前开始和结束(第 2 种情况),您想做什么?
  • 建一个新表。哦,忘了写我会删除那条记录,因为它很可能是错误的。

标签: sql tsql datetime


【解决方案1】:

如果您使用 SQL Server 2012 及更高版本(感谢 Karl 的提示),您可以使用 LAG 和 LEAD,如下所示:

SQL Fiddle

查询 1

select [System], [ID], [Item], 
[Start], 
CASE WHEN LAG([End]) OVER(ORDER BY [Start]) > [Start] AND 
          LAG([System]) OVER(ORDER BY [Start]) = 'Alpha' AND
          [System] = 'Beta'
     THEN LAG([End]) OVER(ORDER BY [Start]) ELSE [Start] END As [CorrectStart],
[End],
CASE WHEN LEAD([Start]) OVER(ORDER BY [Start]) < [End] AND 
          LEAD([System]) OVER(ORDER BY [Start]) = 'Alpha' AND
          [System] = 'Beta'
     THEN LEAD([Start]) OVER(ORDER BY [Start]) ELSE [End] END As [CorrectEnd]
FROM Table1
order by [Start]

Results

| System |  ID | Item |                 Start |          CorrectStart |                   End |            CorrectEnd |
|--------|-----|------|-----------------------|-----------------------|-----------------------|-----------------------|
|  Alpha | 987 |  123 | May, 20 2015 07:00:00 | May, 20 2015 07:00:00 | May, 20 2015 08:00:00 | May, 20 2015 08:00:00 |
|   Beta | 374 |  123 | May, 20 2015 07:30:00 | May, 20 2015 08:00:00 | May, 20 2015 10:00:00 | May, 20 2015 09:00:00 |
|  Alpha | 184 |  123 | May, 20 2015 09:00:00 | May, 20 2015 09:00:00 | May, 20 2015 10:00:00 | May, 20 2015 10:00:00 |
|   Beta | 798 |  123 | May, 20 2015 10:00:00 | May, 20 2015 10:00:00 | May, 20 2015 12:00:00 | May, 20 2015 12:00:00 |

【讨论】:

    【解决方案2】:

    我认为您想找到每个项目的最后一个 alpha 和第一个 beta 并将第一个 beta 开始时间更新为最后一个 alpha 的结束时间。

    这可以简化,当然可以针对性能进行优化。我这样写是因为它非常明确。

    注意:LAG 和 LEAD 是在 SQL Server 2012 中引入的,所以 cha 的解决方案当然可以在您拥有或更高版本的情况下使用。

    --create the sample data
    DECLARE @Tracking TABLE(Name VARCHAR(10),ID INT,Item INT,StartTime DATETIME2,EndTime DATETIME2)
    INSERT INTO @Tracking 
      SELECT * FROM (VALUES
    
      ('Alpha'  , 987 , 123 , '2015-05-20 07:00:00' , '2015-05-20 08:00:00')
     ,('Beta'   , 184 , 123 , '2015-05-20 07:30:00' , '2015-05-20 10:00:00')
     ,('Alpha'  , 374 , 123 , '2015-05-20 08:00:00' , '2015-05-20 09:00:00')
     ,('Beta'   , 798 , 123 , '2015-05-20 10:00:00' , '2015-05-20 12:00:00')
     ) AS tbl(Name,ID,Item,StartTime,EndTime)  
    
    --get row number for the sample data over sytem name and item
    --use a cte for clarity
    ;WITH 
    cte AS (
      SELECT Name,ID,Item,StartTime,EndTime
            ,rn = ROW_NUMBER() OVER (PARTITION BY Item,Name ORDER BY StartTime)
            ,rn_reverse = ROW_NUMBER() OVER (PARTITION BY Item,Name ORDER BY StartTime DESC)
        FROM @Tracking
    ),
    --get only the last alpha
    LastAlphas AS (
      SELECT * FROM cte WHERE Name = 'Alpha' AND rn_reverse = 1
    ),
    --and the forst beta
    FirstBetas AS (
      SELECT * FROM cte WHERE Name = 'Beta' AND rn = 1
    )
    --join them all and do the update
    UPDATE @Tracking
       SET StartTime = a.EndTime
      FROM @Tracking t
      JOIN FirstBetas b ON t.id = b.id
      JOIN LastAlphas a ON t.item = a.item
    
    SELECT * FROM @Tracking ORDER BY Name, StartTime
    
    --Alpha 987 123 2015-05-20 07:00:00.0000000 2015-05-20 08:00:00.0000000
    --Alpha 374 123 2015-05-20 08:00:00.0000000 2015-05-20 09:00:00.0000000
    --Beta  184 123 2015-05-20 09:00:00.0000000 2015-05-20 10:00:00.0000000
    --Beta  798 123 2015-05-20 10:00:00.0000000 2015-05-20 12:00:00.0000000
    

    【讨论】:

      【解决方案3】:

      我们可以通过在下面提到的查询中简单地连接两个表来实现这一点:-

      with cte1 as 
      (
      select *,ROW_NUMBER() over (partition by name order by starttime) as rn
      from #a
      ),cte2 as 
      (
      select a.name,a.id,a.item,min(isnull((case when a.name = 'Beta' then b.endtime else a.starttime end),a.starttime)) as starttime,a.endtime
      from cte1 as a
      left join cte1 as b
      on b.rn = a.rn + 1
      group by a.name,a.id,a.item,a.endtime
      )
      update a
      set a.starttime = b.starttime,
          a.endtime = b.endtime 
      from #a as a
      inner join cte2 as b
      on b.id = a.id
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 2010-09-09
        • 1970-01-01
        • 2010-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多