SQL - 选择两个字符串行之间的所有行

Posted

技术标签:

【中文标题】SQL - 选择两个字符串行之间的所有行【英文标题】:SQL - Select all rows between two string rows 【发布时间】:2015-04-19 21:36:25 【问题描述】:

是否可以返回匹配行之间的所有行?

我正在尝试查询一个审计表,作业在其中写入审计表。有明确的开始审计消息和结束审计消息以及它们之间的信息。是否可以让一个 select 语句返回“开始”审计条目和“结束”条目之间的所有行?

数据示例。

DATE                  TIME   USER                ENTRY                                                                              
----------------------- -------- -------------------- --------------------------------------------------------------------
2015-04-13 07:30:15.150 07:30:15 CmdLne               SOME JOB STARTED FOR PROCESSING DATE 13/04/2015                       
2015-04-13 07:31:15.150 07:31:15 CmdLne               PROCESSED 10 WHATEVERS
2015-04-13 07:32:25.150 07:32:25 CmdLne               PROCESSED 10 SOMETHINGS
2015-04-13 07:33:33.150 07:33:33 CmdLne               PROCESSED 40 XYZ
2015-04-13 07:33:34.150 07:33:34 CmdLne               SOME JOB FINISHED FOR PROCESSING DATE 13/04/2015                       

因为不知道在审计写入期间会有多少审计条目,它必须能够选择“开始”条目和“结束”条目之间的所有内容。这可能吗?

【问题讨论】:

你知道非开始行的开始/结束入口还是入口代码?? 是否存在重叠的审计事件,即用户 Fred 和 Wilma 所做的工作是否会导致审计表同时包含他们俩的记录? 单个用户是否会导致重叠的审计事件,例如长期运行的报告和导入新数据,如果是,您将如何整理它们? 【参考方案1】:

这是一个简单而干净的解决方案。如果您有任何问题或需要其他任何东西,请告诉我。

SELECT  A.[DATE],
        A.[TIME],
        A.[User],
        A.[Entry]
FROM @Table A
CROSS APPLY(SELECT MIN([Date]) FROM @Table WHERE [Entry] LIKE 'Some Job%') CA_min(start_dt)
CROSS APPLY(SELECT MAX([Date]) FROM @Table WHERE [Entry] LIKE 'Some Job%') CA_max(end_dt)
WHERE [DATE] BETWEEN start_dt AND end_dt

【讨论】:

CROSS APPLY 基本上就像一个子查询,但使用交叉应用允许我在 where 子句中引用它。你熟悉子查询吗?【参考方案2】:

试试ORDER-BYASC / DESC

WITH Data (Date, Time, User, Entry) AS
    (
    SELECT Date, Time, User, Entry
    FROM data
    ORDER BY DATE ASC, TIME ASC
    ) 

SELECT TOP ((SELECT COUNT(*) FROM Data) - 2) *
FROM (
    SELECT TOP ((SELECT COUNT(*) FROM Data) - 1) *
    FROM Data
    ORDER BY Date ASC, Time ASC  -- all rows without the end-row
    ) tmp
ORDER BY Date ASC, Time DESC -- all rows without the start-row

或者更简单的WHERE-Clause。

SELECT Date, Time, User, Entry
FROM data
WHERE Entry NOT LIKE '%JOB STARTED%' 
  AND Entry NOT LIKE '%JOB FINISHED%'

【讨论】:

【参考方案3】:

测试数据

DECLARE @Table TABLE ([DATE] Datetime ,[TIME] TIME, [USER] VARCHAR(100) , [ENTRY] VARCHAR(1000))
INSERT INTO @Table VALUES                                                                              
('2015-04-13 07:30:15.150','07:30:15','CmdLne','SOME JOB STARTED FOR PROCESSING DATE 13/04/2015'),                       
('2015-04-13 07:31:15.150','07:31:15','CmdLne','PROCESSED 10 WHATEVERS'),
('2015-04-13 07:32:25.150','07:32:25','CmdLne','PROCESSED 10 SOMETHINGS'),
('2015-04-13 07:33:33.150','07:33:33','CmdLne','PROCESSED 40 XYZ'),
('2015-04-13 07:33:34.150','07:33:34','CmdLne','SOME JOB FINISHED FOR PROCESSING DATE 13/04/2015') ,
('2015-04-13 07:30:15.150','07:30:15','Powershell','SOME JOB STARTED FOR PROCESSING DATE 13/04/2015'),                       
('2015-04-13 07:31:15.150','07:31:15','Powershell','PROCESSED 10 WHATEVERS'),
('2015-04-13 07:32:25.150','07:32:25','Powershell','PROCESSED 10 SOMETHINGS'),
('2015-04-13 07:33:33.150','07:33:33','Powershell','PROCESSED 40 XYZ'),
('2015-04-13 07:33:34.150','07:33:34','Powershell','SOME JOB FINISHED FOR PROCESSING DATE 13/04/2015') 

查询

SELECT t1.*
FROM @Table t1
WHERE t1.[DATE] >= ( SELECT TOP 1 [DATE] FROM @Table
                     WHERE [ENTRY] LIKE '%SOME JOB STARTED%'
                      AND  t1.[USER] = [USER])
 AND t1.[DATE] <= ( SELECT TOP 1 [DATE] FROM @Table
                     WHERE [ENTRY] LIKE '%SOME JOB FINISHED%'
                      AND  t1.[USER] = [USER])
 AND t1.[USER] = 'CmdLne'  --<-- 

【讨论】:

【参考方案4】:

数据样本

DECLARE @Table TABLE
    (
      [DATE] DATETIME ,
      [TIME] TIME ,
      [USER] VARCHAR(100) ,
      [ENTRY] VARCHAR(1000)
    )
INSERT  INTO @Table
VALUES  ( '2015-04-13 07:30:15.150', '07:30:15', 'CmdLne',
          'SOME JOB STARTED FOR PROCESSING DATE 13/04/2015' ),
        ( '2015-04-13 07:31:15.150', '07:31:15', 'CmdLne',
          'PROCESSED 10 WHATEVERS' ),
        ( '2015-04-13 07:32:25.150', '07:32:25', 'CmdLne',
          'PROCESSED 10 SOMETHINGS' ),
        ( '2015-04-13 07:33:33.150', '07:33:33', 'CmdLne', 'PROCESSED 40 XYZ' ),
        ( '2015-04-13 07:33:34.150', '07:33:34', 'CmdLne',
          'SOME JOB FINISHED FOR PROCESSING DATE 13/04/2015' ) ,
        ( '2015-04-13 07:30:15.150', '07:30:15', 'Powershell',
          'SOME JOB STARTED FOR PROCESSING DATE 13/04/2015' ),
        ( '2015-04-13 07:31:15.150', '07:31:15', 'Powershell',
          'PROCESSED 10 WHATEVERS' ),
        ( '2015-04-13 07:32:25.150', '07:32:25', 'Powershell',
          'PROCESSED 10 SOMETHINGS' ),
        ( '2015-04-13 07:33:33.150', '07:33:33', 'Powershell',
          'PROCESSED 40 XYZ' ),
        ( '2015-04-13 07:33:34.150', '07:33:34', 'Powershell',
          'SOME JOB FINISHED FOR PROCESSING DATE 13/04/2015' ) 

最终查询

SELECT  *
FROM    ( SELECT    ROW_NUMBER() OVER ( PARTITION BY CONVERT(DATE, T.DATE),
                                        T.[USER] ORDER BY T.DATE ) AS RN ,
                    *
          FROM      @Table AS T
        ) T
WHERE   T.RN NOT IN ( 1, 2 )

【讨论】:

以上是关于SQL - 选择两个字符串行之间的所有行的主要内容,如果未能解决你的问题,请参考以下文章

删除 Hive SQL 查询中两个子字符串之间的所有字符

在oracle sql中将字符串行连接到最大长度

选择 PL/SQL 中两个非空列值之间的行集

linux如何截取指定字符串行前后N行的数据

如何选择从串口接收的号码

从C#中的字符串行中获取特定字段或字符