删除SQL Server中的重复项 - 异常方案

时间:2010-01-05 05:02:13

标签: sql sql-server sql-server-2005

我目前正在研究的数据库是用于在某些时间点记录数据的科学仪器。我的仪器每秒记录一次,但分辨率为5秒。

ID      Total Particles  DateandTime
38313   602              2009-01-27 16:25:48.000
38314   602              2009-01-27 16:25:49.000
38315   602              2009-01-27 16:25:50.000
38316   602              2009-01-27 16:25:51.000
38317   602              2009-01-27 16:25:52.000
38318   553              2009-01-27 16:25:53.000
38319   553              2009-01-27 16:25:54.000
38320   553              2009-01-27 16:25:55.000
38321   553              2009-01-27 16:25:56.000
38322   553              2009-01-27 16:25:57.000
38323   515              2009-01-27 16:25:58.000
38324   515              2009-01-27 16:25:59.000
38325   515              2009-01-27 16:26:00.000
38326   515              2009-01-27 16:26:01.000
38327   515              2009-01-27 16:26:02.000

在某些情况下,这对我们很有用,但与项目的这一部分无关。我想折叠这些数据,以便每5秒钟有一个结果(比如说最后一秒可以保存所有数据用于约定)。

我更喜欢一个没有跳过4行的解决方案并且显示第5行,因为如果我的文章搞砸了并且只在db中给了我4行,那可能无效。我想要的是比较每个样品周围的行和基于此的冷凝的一些方法。

我真的不知道从哪里开始这样的操作,所以任何帮助都会受到赞赏。

6 个答案:

答案 0 :(得分:2)

对重复使用通常的ROW_NUMBER()分区,并使用适当的分区方案。

with cte as (
 select ID, Total, Particles, DateandTime,
   row_number() over (
    partition by datediff(seconds,'19000101',DateandTime)/5
    order by DateandTime) as rn
 from table)
select * from cte
where rn = 1; 

无法评论这对于了解表格的确切模式(包括索引)的效率。

答案 1 :(得分:1)

如果流是可预测的,您可以执行以下操作:

select id, particles, time from log where
id in (select min(id) from log group by
datediff(second, (select min(time) from log), time) / 5)

将从每5秒间隔获得第一个读数。第一个间隔覆盖日志中的秒数1 - 5。下一个间隔是秒6-10等,没有重叠。

你可以做一个类似的查询来获得每个区间的平均值,但由于你希望同一区间内的读数相同,所以avg可以在有缺失或错误条目的情况下混合数据,所以只需要第一次或最后一次阅读可能更好。

答案 2 :(得分:1)

我发表评论 - 即使你没有获得5行,我也会假设物理数据点仍然需要5秒钟。如果是这样,以下可能会有效。

首先,创建一个秒函数:

CREATE FUNCTION dbo.GetTotalSeconds(@dt datetime)
RETURNS bigint
AS
BEGIN
    RETURN DATEDIFF(ss, '1753-01-01', @dt)
END

现在这个查询:

DECLARE
    @StartID int,
    @EndID int

SET @StartID = 38313
SET @EndID = 40313

DECLARE @StartSeconds bigint

SELECT TOP 1 @StartSeconds = dbo.GetSeconds(DateandTime)
FROM DataPoints
WHERE ID >= @StartID
ORDER BY ID ASC

SELECT p.ID, p.Total, p.Particles, p.DateandTime
FROM
(
    SELECT DISTINCT
        (dbo.GetSeconds(DateandTime) - @StartSeconds) / 5 AS SecondsInterval
    FROM DataPoints
    WHERE ID >= @StartID
    AND ID <= @EndID
) g
INNER JOIN DataPoints p
ON (dbo.GetSeconds(p.DateandTime) - @StartSeconds) = g.SecondsInterval
ORDER BY g.SecondsInterval

性能相当弱但它应该处理所有边缘情况。

答案 3 :(得分:1)

好的,所以我有时间将我的MatLab解决方案转换为SQL。不太确定它是否真的那么棒,但效果很好。我的MatLab解决方案花了30多分钟来计算我拥有的220万行的结果,SQL版本用了4分钟!

如果有人在将来遇到类似问题,请参考以下代码:

DECLARE @i INT
DECLARE @Count INT
DECLARE @Selection INT
DECLARE @Result TABLE (ID INT)

SET @i = 1
SET @Count = (SELECT count(*) FROM CFLAPS_AllStations)

WHILE (@i <= @Count)
BEGIN
   IF @i < @Count - 4
    BEGIN
        SET @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i)
        IF  @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+4)
        BEGIN   
            INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i
        END
        ELSE
        BEGIN
            INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i

            SET @i =  
            CASE 
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+3) THEN @i-1
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+2) THEN @i-2
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+1) THEN @i-3
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i) THEN @i-4
            END
        END
   END
   ELSE
   BEGIN
      INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i
   END
   SET @i = @i+5
END

SELECT p.ID, p.TotalParticlesCount, p.FullDateTime FROM CFLAPS_AllStations as p, @Result as q WHERE p.ID = q.ID

所以你们都知道为什么这很重要:仪器总是会记录5秒钟的相同数据,但是如果它停止记录,比如说周期的第二个3;它不会记录第4和第5秒因此出现数据缺口。我设法用这个while循环检查了它,并设法捕获所有这些不一致。

最终输出:

ID  TotalParticles  DateTime
1       745     2009-06-23 00:00:00.000
6       727     2009-06-23 00:00:05.000
11      771     2009-06-23 00:00:10.000
16      837     2009-06-23 00:00:15.000
21      768     2009-06-23 00:00:20.000
26      703     2009-06-23 00:00:25.000
31      822     2009-06-23 00:00:30.000
36      730     2009-06-23 00:00:35.000
41      731     2009-06-23 00:00:40.000
46      706     2009-06-23 00:00:45.000
51      733     2009-06-23 00:00:50.000
...
2290089 677     2009-06-22 23:59:15.000
2290094 720     2009-06-22 23:59:20.000
2290099 771     2009-06-22 23:59:25.000
2290104 770     2009-06-22 23:59:30.000
2290109 761     2009-06-22 23:59:35.000
2290114 851     2009-06-22 23:59:40.000
2290119 801     2009-06-22 23:59:45.000
2290124 754     2009-06-22 23:59:50.000
2290129 702     2009-06-22 23:59:55.000

感谢所有帮助过的人。

答案 4 :(得分:0)

可能最好的方法(如果你想保留所有'原始'数据)是在插入'raw'表时有一些插入到'summary'表中的触发器。此触发器将根据时间识别传递信息的基础。这意味着你将获得大量数据,但我希望保持它是合适的。值得注意的是,通过触发器执行此操作可能会很糟糕(缓慢),因为每次插入都会发生这种情况。在应用程序级别捕获此信息可能更合适,但我不知道这是否可能......

答案 5 :(得分:0)

感谢您的帮助。我想如果我在这个问题上有更多的时间,我就可以使用你所有的样本并在SQL中直接使用 - 但我真的没有那种自由。我正在研究的项目主要是用MatLab编写的,所以我所做的就是从数据库中提取ID和TotalParticles数据,然后在Matlab中运行对TotalParticles列的检查。此脚本的输出是我对折叠数据库所需的ID值,我将其输入到一个简单的select语句中,然后它将生成我需要的视图。