【问题标题】:Add additional row添加额外的行
【发布时间】:2017-03-19 11:28:01
【问题描述】:

我有以下数据(视图):

 Declare @YourTable table ([Event] varchar(100),[Start] DateTime,[End] DateTime, [Tag] varchar(25))
  Insert Into @YourTable values
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:05.000','9/9/16 10:48:08.000','Big'),
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:10.000','9/9/16 10:49:40.000','Big'),
  ('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:50:03.000','9/9/16 10:51:04.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 12:51:07.000','4/4/16 13:58:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:04:04.000','4/4/16 14:29:00.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:51:02.000','4/4/16 14:58:00.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 15:04:06.000','4/4/16 15:29:08.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 15:45:08.000','4-4-16 15:55:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 16:22:08.000','4-4-16 16:40:09.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 16:50:04.000','4/4/16 16:55:00.000','Small'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:05:02.000','4/4/16 17:20:00.000','Big'),
  ('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:22:06.000','4/4/16 17:29:08.000','Small'),
  ('11PIC41010.PV 11-PSV-401002W 11-PSV-401002D','4/4/16 16:04:01.000','4/4/16 16:45:00.000','Big');

我使用以下查询来获取我需要的结果,按事件分组并按开始顺序,并在小到大时从大到小:

 Select [Event]
  ,[Start]
  ,[End] 
  ,[Tag]
  ,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By Event Order By Start) then 'Small' else tag end
  From  @YourTable

                                       Event    Start                   End                     Tag  Tag_new
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:05.000 2016-09-09 10:48:08.000 Big   Big
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:10.000 2016-09-09 10:49:40.000 Big   Small
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:50:03.000 2016-09-09 10:51:04.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 12:51:07.000 2016-04-04 13:58:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:04:04.000 2016-04-04 14:29:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:51:02.000 2016-04-04 14:58:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:04:06.000 2016-04-04 15:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:45:08.000 2016-04-04 15:55:09.000 Big   Big
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:22:08.000 2016-04-04 16:40:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:50:04.000 2016-04-04 16:55:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:05:02.000 2016-04-04 17:20:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:22:06.000 2016-04-04 17:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002W 11-PSV-401002D     2016-04-04 16:04:01.000 2016-04-04 16:45:00.000 Big   Big

我需要再应用一个例外,每当下面的序列出现在组中的 Tag 列中时,它应该在 small 之后和 big 之前添加相应的 starttime、endtime 和 Tag_new 的附加行,并且 starttime 应该比上一个日期晚 1 秒endtime 和 endtime 比 starttime 晚 1 秒,并且 Tag_new 为“Bad”:

Small
Big
Small

我想得到类似下面的东西:

                                       Event    Start                   End                     Tag  Tag_new
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:05.000 2016-09-09 10:48:08.000 Big   Big
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:44:10.000 2016-09-09 10:49:40.000 Big   Small
10PIC700422.PV 10-PSV-700073A 10-PSV-700073B    2016-09-09 10:50:03.000 2016-09-09 10:51:04.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 12:51:07.000 2016-04-04 13:58:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:04:04.000 2016-04-04 14:29:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:29:01.000 2016-04-04 14:29:02.000 Bad   Bad
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 14:51:02.000 2016-04-04 14:58:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:04:06.000 2016-04-04 15:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 15:45:08.000 2016-04-04 15:55:09.000 Big   Big
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:22:08.000 2016-04-04 16:40:09.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:50:04.000 2016-04-04 16:55:00.000 Small Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 16:55:01.000 2016-04-04 16:55:02.000 Bad   Bad
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:05:02.000 2016-04-04 17:20:00.000 Big   Small
11PIC41010.PV 11-PSV-401002A 11-PSV-401002B     2016-04-04 17:22:06.000 2016-04-04 17:29:08.000 Small Small
11PIC41010.PV 11-PSV-401002W 11-PSV-401002D     2016-04-04 16:04:01.000 2016-04-04 16:45:00.000 Big   Big

【问题讨论】:

  • 我投了赞成票,因为这个问题很好。有复制'n'粘贴的示例代码,自己的努力和非常清晰的解释。整个方法有点味道,而且 - 嗯 - 复杂...... SQL Server 可能不是最好的工具。但这个问题本身既不值得“因为不清楚而关闭”,也不值得投反对票。只是我的 2 美分...
  • 感谢 Shnugo 的支持
  • 你为什么要转发这个问题,在这里得到了回答:stackoverflow.com/questions/40026002/…
  • 对不起 iamdave,经过今天的几次测试,我发现将 small2 更改为 small2 不是我需要的,因为如果有 small-big-small-big-small-big-small,它会给出 small2两组,这是错误的方向,正确的是在小之后和大之前添加行。

标签: sql-server tsql sql-server-2012


【解决方案1】:

这个设计有味道,但你可以试试这样:

您应该避免使用特定于文化的日期时间文字!

Declare @YourTable table ([Event] varchar(100),[Start] DateTime,[End] DateTime, [Tag] varchar(25))
Insert Into @YourTable values
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:05.000','9/9/16 10:48:08.000','Big'),
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:44:10.000','9/9/16 10:49:40.000','Big'),
('10PIC700422.PV 10-PSV-700073A 10-PSV-700073B','9/9/16 10:50:03.000','9/9/16 10:51:04.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 12:51:07.000','4/4/16 13:58:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:04:04.000','4/4/16 14:29:00.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 14:51:02.000','4/4/16 14:58:00.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 15:04:06.000','4/4/16 15:29:08.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 15:45:08.000','4-4-16 15:55:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4-4-16 16:22:08.000','4-4-16 16:40:09.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 16:50:04.000','4/4/16 16:55:00.000','Small'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:05:02.000','4/4/16 17:20:00.000','Big'),
('11PIC41010.PV 11-PSV-401002A 11-PSV-401002B','4/4/16 17:22:06.000','4/4/16 17:29:08.000','Small'),
('11PIC41010.PV 11-PSV-401002W 11-PSV-401002D','4/4/16 16:04:01.000','4/4/16 16:45:00.000','Big');

--为您的查询添加一个正在运行的行号,并为所有 original 行添加一个 0

WITH YourQueryEnhanced AS
(
    Select [Event]
    ,[Start]
    ,[End] 
    ,[Tag]
    ,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By [Event] Order By Start) then 'Small' else tag end
    ,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SortInx --You should put a secure ORDER BY here!!!
    ,0 AS InnerSortInx
    From  @YourTable
)

--使用LAG() 检测您的序列。重叠坏序列存在一个问题!

,BadMarked AS
(
    SELECT *
        ,CASE WHEN LAG([Tag],1) OVER(Order By SortInx)='Small' 
                AND LAG([Tag],2) OVER(Order By SortInx)='Big' 
                AND LAG([Tag],3) OVER(Order By SortInx)='Small' THEN 1 ELSE 0 END AS BadSequence 

    FROM YourQueryEnhanced
)

--这将选择所有original 行,并为标记为BadSequence 的每一行添加一个bad 行。 SortInx 设置为 prev 值,内部 sortInx 设置为1,因此ORDER BY 会将bad 行推送到适当的位置

    SELECT *
    FROM BadMarked

    UNION ALL 

    SELECT [Event],[Start],[End],'Bad','Bad',SortInx-1,1,2 
    FROM BadMarked 
    WHERE BadMarked.BadSequence=1
    ORDER BY SortInx,InnerSortInx

注意

正如您在预期结果中所说的那样,这将为您的结果添加一个错误的行。

原因是您的第 3 到第 7 行有 small-big-small-big-small。中间的small 属于这两个序列。

您必须在检测到错误序列的地方使用更多逻辑(更多调用LAG() 以进一步回顾)来解决此问题,或者将最后一个选择包装为另一个CTE 并使用@987654337 @ 再次删除你不想要的坏行。

【讨论】:

  • Shnugo,谢谢你的代码,但这似乎不是我需要的。
  • @JoeGreen,请详细说明...为什么不呢?
  • 好的,我会尝试处理额外的行(仍然不知道该怎么做),如何将开始时间和结束时间增加 1 秒?
  • @JoeGreen 尝试 dateadd()
【解决方案2】:

@Shnugo:你真的很亲密。谢谢解决!!!

WITH YourQueryEnhanced AS
(
Select [Event]
,[Start]
,[End] 
,[Tag]
,[Tag_new] = case when Tag='Big' and 'Small' = Lead(Tag,1,Tag) over (Partition By [Event] Order By Start) then 'Small' else tag end
,ROW_NUMBER() OVER(Partition By [Event] Order By Start) AS SortInx --You     should put a secure ORDER BY here!!!
,0 AS InnerSortInx
From  @YourTable
), BadMarked AS
(
 SELECT *
    ,CASE WHEN LAG([Tag],1) OVER(Order By SortInx)='Small' 
            AND LAG([Tag],2) OVER(Order By SortInx)='Big' 
            AND LAG([Tag],3) OVER(Order By SortInx)='Big' THEN 1 ELSE 0 END     AS BadSequence 
FROM YourQueryEnhanced 
) 
select * from
(
SELECT *
FROM BadMarked
UNION ALL 
    SELECT [Event],DATEADD(s, -1, [Start]) [Start],    [End],'Bad','Bad',SortInx-1,1,2 
FROM BadMarked 
WHERE BadMarked.BadSequence=1
) a order by [Event]
,[Start]

【讨论】:

    猜你喜欢
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多