Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
识别SQL Server中的序列开始和结束_Sql_Sql Server - Fatal编程技术网

识别SQL Server中的序列开始和结束

识别SQL Server中的序列开始和结束,sql,sql-server,Sql,Sql Server,我有一个表,其中的数据按如下方式排列: ID | BOUNDARY | TIMESTAMP 1 | NULL | 2016-01-01 00:20:00 2 | A | 2016-01-01 00:20:10 3 | A | 2016-01-01 00:20:14 4 | A | 2016-01-01 00:20:22 5 | NULL | 2016-01-01 00:20:38 6 | A

我有一个表,其中的数据按如下方式排列:

ID |  BOUNDARY  | TIMESTAMP
1  |  NULL      | 2016-01-01 00:20:00
2  |  A         | 2016-01-01 00:20:10
3  |  A         | 2016-01-01 00:20:14
4  |  A         | 2016-01-01 00:20:22
5  | NULL       | 2016-01-01 00:20:38
6  |  A         | 2016-01-01 00:20:45
7  |  B         | 2016-01-01 00:21:02
8  |  B         | 2016-01-01 00:21:12
9  |  A         | 2016-01-01 00:21:16
10 |  A         | 2016-01-01 00:21:22
11 |  C         | 2016-01-01 00:21:30
12 |  A         | 2016-01-01 00:21:35
13 |  A         | 2016-01-01 00:21:40
14 |  A         | 2016-01-01 00:21:46
15 |  A         | 2016-01-01 00:21:50
我想做的是找到一种有效的方法来标记SQL Server 2014中序列开始和结束的ID和时间戳。当一个边界不为空并且至少连续重复两次时,一个段将被删除。例如,第一段来自IDs 2-4,第二段来自IDs 7-8,第三段来自IDs 9-10

我首先尝试的方法是创建两列,一个startflag col和一个endflag列。我创建了一个正确标记开始和结束的更新查询,但我想创建一个视图,在其中我可以将其视为一条记录,如下所示:

BOUNDARY | START ID | END ID  
A        |   2      |  4
B        |   7      |  8
A        |   9      |  10
A        |   12     |  15

好的,我相信有更好的方法可以做到这一点,但这是可行的:

WITH CTE AS
(
    SELECT  *,
            RN1 = ROW_NUMBER() OVER(ORDER BY [TIMESTAMP]),
            RN2 = ROW_NUMBER() OVER(PARTITION BY BOUNDARY ORDER BY [TIMESTAMP])
    FROM #YourTable
), CTE2 AS
(
    SELECT  *, 
            RN1-RN2 RN3,
            COUNT(*) OVER(PARTITION BY RN1-RN2) N
    FROM CTE
)
SELECT  BOUNDARY,
        MIN(ID) [START ID],
        MAX(ID) [END ID]
FROM CTE2
WHERE N > 1
AND BOUNDARY IS NOT NULL
GROUP BY BOUNDARY, RN3
ORDER BY [START ID];
如果我们使用此示例表:

CREATE TABLE #YourTable
    ([ID] int, [BOUNDARY] varchar(4), [TIMESTAMP] datetime)
;

INSERT INTO #YourTable
    ([ID], [BOUNDARY], [TIMESTAMP])
VALUES
    (1, NULL, '2016-01-01 00:20:00'),
    (2, 'A', '2016-01-01 00:20:10'),
    (3, 'A', '2016-01-01 00:20:14'),
    (4, 'A', '2016-01-01 00:20:22'),
    (5, NULL, '2016-01-01 00:20:38'),
    (6, 'A', '2016-01-01 00:20:45'),
    (7, 'B', '2016-01-01 00:21:02'),
    (8, 'B', '2016-01-01 00:21:12'),
    (9, 'A', '2016-01-01 00:21:16'),
    (10, 'A', '2016-01-01 00:21:22'),
    (11, 'C', '2016-01-01 00:21:30'),
    (12, 'A', '2016-01-01 00:21:35'),
    (13, 'A', '2016-01-01 00:21:40'),
    (14, 'A', '2016-01-01 00:21:46'),
    (15, 'A', '2016-01-01 00:21:50')
;
结果是:

╔══════════╦══════════╦════════╗
║ BOUNDARY ║ START ID ║ END ID ║
╠══════════╬══════════╬════════╣
║ A        ║        2 ║      4 ║
║ B        ║        7 ║      8 ║
║ A        ║        9 ║     10 ║
║ A        ║       12 ║     15 ║
╚══════════╩══════════╩════════╝

关键是通过以下方式创建岛屿分组:

根据您的ID时间计算行号 计算每个不同值的行数 分组=1-2 请看下面的示例:

declare @T table (ID int, BOUNDARY char(1), [TIMESTAMP] datetime2)
insert into @T values (1, null, '2016-01-01 00:20:00'), (2, 'A', '2016-01-01 00:20:10'), (3, 'A', '2016-01-01 00:20:14'), (4, 'A', '2016-01-01 00:20:22'), (5, null, '2016-01-01 00:20:38'), (6, 'A', '2016-01-01 00:20:45'), (7, 'B', '2016-01-01 00:21:02'), (8, 'B', '2016-01-01 00:21:12'), (9, 'A', '2016-01-01 00:21:16'), (10, 'A', '2016-01-01 00:21:22'), (11, 'C', '2016-01-01 00:21:30'), (12, 'A', '2016-01-01 00:21:35'), (13, 'A', '2016-01-01 00:21:40'), (14, 'A', '2016-01-01 00:21:46'), (15, 'A', '2016-01-01 00:21:50')

select 
    BOUNDARY, 
    min(ID) as [START ID], 
    max(id) as [END ID]
from
(
    select 
        ID, 
        BOUNDARY, 
        ID - 
        row_number() over (partition by BOUNDARY order by TIMESTAMP) as grp
    from @T as t
) as T
where BOUNDARY is not null
group by grp, BOUNDARY
having count(*) >= 2
order by min(ID)

为什么最终答案中不包括边界=C?因为没有两条记录?因为一行中至少需要有两个实例。+1但我认为按时间戳排序应该是ID,特别是当时间戳可能出现问题时,例如,将记录3更改为1天后,您会得到一个令人不快的结果。@Aducci,谢谢,但不完全是这样。我在上面尝试过,它将所有“A”边界分组为一个记录,开始为2,结束为15。实际上,我需要在上面的3个单独的“A”记录。但是,这是一个开始,我可能可以使用它。@user3150002-脚本为我输出正确的结果。不确定您运行的是什么?+1,但我认为按时间戳排序应该是ID,特别是当时间戳可能出现问题时,例如,将记录3更改为1天后,您会得到一个令人不快的结果。@Lamak:我对数据的一小部分进行了测试,它似乎有效!我的表有数千行数据,所以让我运行整个集合并验证。@user3150002没有问题。慢慢来,根据需要进行测试