修改记录以说明两个系统之间的正确优先级和顺序

时间:2015-06-10 00:32:53

标签: sql tsql datetime

我有两个表跟踪不同系统中的项目,为简单起见,我们称之为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记录开始之前开始和结束的位置。

有意义吗?我希望如此,过去几天它让我疯了。

感谢您提供任何帮助。

3 个答案:

答案 0 :(得分:0)

如果您使用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 |

答案 1 :(得分:0)

我想你想找到每个项目的最后一个alpha和第一个beta,并用最后一个alpha的结束时间更新第一个beta开始时间。

这可以简化,当然也会针对性能进行优化。我这样离开了,因为它非常明确。

注意: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

答案 2 :(得分:0)

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

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