sql-server - 光标的替代品吗?

标签 sql-server

我正在尝试找到一种无需使用光标即可完成此操作的方法。

我有一组数据,总计约 1300 万条记录。一条记录与下一条记录之间的间隔各不相同,但都在 5 到 20 分钟之间。 我需要创建一个新的数据表,但选择数据以使一条记录与下一条记录之间至少有 30 分钟的间隔。

例如,如果我有这个:

VID | Datetime
1   |  2016-01-01 00:00
1   |  2016-01-01 00:10
1   |  2016-01-01 00:12
1   |  2016-01-01 00:25
2   |  2016-01-01 00:40
4   |  2016-01-01 01:00
4   |  2016-01-01 02:13
6   |  2016-01-01 02:23
7   |  2016-01-01 02:25
8   |  2016-01-01 02:49
9   |  2016-01-01 02:59
9   |  2016-01-01 03:01
9   |  2016-01-01 03:09
9   |  2016-01-01 03:24
9   |  2016-01-01 04:05

新表将如下所示:

VID | Datetime
1   |  2016-01-01 00:00
2   |  2016-01-01 00:40
4   |  2016-01-01 02:13
8   |  2016-01-01 02:49
9   |  2016-01-01 03:24

我可以使用游标来完成此操作,但对于数百万条记录来说这太疯狂了。我见过有人提到类似情况下的“古怪更新”,但我不确定那是什么。

当前使用 SQL Server 2014。任何帮助将不胜感激。

最佳答案

跳出框框思考一下,如果允许在每 30 分钟间隔内获取最早的行,那么我就有一个可行的解决方案。

注意事项:

  • 此时我假设您的数据可能可以追溯到 30 年前。 1300 万个间隔接近计数表配置方式的极限,因此如果超过 1600 万个,您将需要进行更改
  • 您可能需要将 CTE 分解为临时表并添加索引才能在该数据上获得良好的性能:-)

--

--setup data
declare @t table (VID int, [Datetime] datetime);
insert  @t values
        (1, '1986-01-01 00:00'),    --very early year
        (1, '2016-01-01 00:10'),
        (1, '2016-01-01 00:12'),
        (1, '2016-01-01 00:25'),
        (2, '2016-01-01 00:40'),
        (4, '2016-01-01 01:00'),
        (4, '2016-01-01 02:13'),
        (6, '2016-01-01 02:23'),
        (7, '2016-01-01 02:25'),
        (8, '2016-01-01 02:49'),
        (9, '2016-01-01 02:59'),
        (9, '2016-01-01 03:01'),
        (9, '2016-01-01 03:09'),
        (9, '2016-01-01 03:24'),
        (9, '2016-01-01 04:05');
select  * from @t order by VID, [Datetime];
--select    datediff(MI, (select min([Datetime]) from @t), (select max([Datetime]) from @t));   --15778325 records in 30 years - handled by t4 x t4 x t4 in tally generator

-- Tally generator courtesy of http://www.sqlservercentral.com/blogs/never_say_never/2010/03/19/tally_2D00_table_2D00_cte/
-- Tally Table CTE script (SQL 2005+ only)
-- You can use this to create many different numbers of rows... for example:
-- You could use a 3 way cross join (t3 x, t3 y, t3 z) instead of just 2 way to generate a different number of rows.
-- The # of rows this would generate for each is noted in the X3 comment column below.
-- For most common usage, I find t3 or t4 to be enough, so that is what is coded here.
-- If you use t3 in ‘Tally’, you can delete t4 and t5.
; WITH
    -- Tally table Gen            Tally Rows:     X2                X3
t1 AS (SELECT 1 N UNION ALL SELECT 1 N),    -- 4            ,    8
t2 AS (SELECT 1 N FROM t1 x, t1 y),            -- 16            ,    64
t3 AS (SELECT 1 N FROM t2 x, t2 y),            -- 256            ,    4096
t4 AS (SELECT 1 N FROM t3 x, t3 y),            -- 65536        ,    16,777,216
t5 AS (SELECT 1 N FROM t4 x, t4 y),            -- 4,294,967,296,    A lot
Tally AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) N
          FROM t4 x, t4 y, t4 z), -- Change the t3's to one of the other numbers above for more/less rows
--generate time values
Intervals as (
        select  t.N - 1 interval,
                dateadd(mi, (t.N - 1) * 30, min_date.min_date) interval_start,
                dateadd(mi, (t.N) * 30, min_date.min_date) next_interval_start
        from    (
                select  min([Datetime]) min_date
                from    @t
                ) min_date
        join    Tally t
                on  t.N <= datediff(MI, (select min([Datetime]) from @t), (select max([Datetime]) from @t)) / 30 + 1
),
--join intervals to data tables
Intervaled_data as (
        select  *, row_number() over (partition by i.interval order by t.[Datetime]) row_num
        from    @t t
        join    Intervals i
                on  t.[Datetime] >= i.interval_start and t.[Datetime] < i.next_interval_start
)
select  i.VID, i.[Datetime]
from    Intervaled_data i
where   i.row_num = 1
order   by i.VID, i.[Datetime];

关于sql-server - 光标的替代品吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41152196/

相关文章:

java - 使用 Java 查找 SQL Server

php - 将日期时间列作为表中的外键是否安全?

sql - 如何向使用 SELECT INTO 创建的表添加完整的主键

c# - 如何设计规则引擎?

sql-server - SQL Server参数化查询不使用非聚集过滤

c# - 为 SQL Server 数据库列手动实现类似 IDENTITY 的增量时避免竞争条件

c# - 如何使用 EntityFramework 核心在插入中强制使用默认值?

sql-server - SQL : All the suggested GetDate () methods are not working

c# - 系统.安全.HostProtectionException : Attempted to perform an operation that was forbidden by the CLR host

Azure 应用服务中的 ASP.NET API 应用