2010-01-05 39 views
2

我目前正在使用的數據庫是用於在某些時間點記錄數據的科學儀器。我的儀器每秒記錄一次,但分辨率爲5秒。刪除SQL Server中的重複項 - 不尋常的場景

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,因爲如果我的instument搞砸了,只給了我4分貝的數據庫可能無法正常工作。我想要的是某種方式比較每個樣本週圍的行和基於此的濃度。

我真的不知道從哪裏開始這樣的操作,所以任何幫助將不勝感激。

+0

艱難的。連續兩個「真實」數據點可以有相同的總數嗎?換句話說,你可以連續讀取10次而不是5次嗎? – Aaronaught 2010-01-05 05:10:28

+0

此外,您還擔心儀器可能只給出4行 - 時間是否仍然正確,即即使您沒有獲得全部5行,樣本佔用的總時間間隔仍爲5秒? – Aaronaught 2010-01-05 05:12:12

+0

你用什麼工具記錄粒子數到MSSQL?您的樂器製造商是否沒有聽說過NetCDF或其他標準科學數據格式? – BobMcGee 2010-01-05 05:17:20

回答

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 

謝謝所有幫助了。

0

也許最好的方法(如果你想保留所有的'原始'數據)是當插入'raw'表時插入'摘要'表的某種觸發器。這個觸發器將根據時間辨別傳遞信息的基礎。這意味着你會得到大量的數據,但我認爲適當的保持它。值得注意的是,通過觸發器來做這件事可能會很糟(緩慢),因爲每次插入都會發生這種情況。這可能是更合適的陷阱在應用層信息,但我不知道這是可能的...

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秒等,沒有重疊。

你可以做一個類似的查詢來獲得每個區間的平均值,但是因爲你期望在相同區間內的讀數是相同的,所以只要有缺失或者時間不匹配的情況,平均值就可以混合數據,採取第一次或最後一次閱讀可能會更好。

+0

這對我的數據做得相當好,但不是100%。正如你所說,如果數據是可預測的,這將工作得很好;但不幸的是我的數據並不那麼寬容。謝謝。 – Geodesic 2010-01-06 04:14:02

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 

性能將是非常微弱的,但它應該處理所有的邊緣情況。

+0

這真的幫我找出了問題。似乎沒有像我期望的那樣工作 - 它似乎在StartID之後找到5個相似的值然後停止。我相信稍微多一點工作,這將是更好的解決方案。 – Geodesic 2010-01-06 04:19:02

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; 

不能評論這是多高效的知道確切的模式(包括索引)的表。

+0

這個答案與我所需要的最接近,但是當我的數據不完全符合它的要求時,它一直存在問題。謝謝您的幫助! – Geodesic 2010-01-06 04:16:47

+0

我忘了用5除以將所有記錄以相同的5秒間隔組合在一起。更新。 – 2010-01-06 07:04:49

0

感謝您的幫助。我認爲,如果我在這個問題上多花一點時間,我將能夠使用所有的示例,並直接在SQL中做一些工作 - 但我並沒有真正的自由。我正在研究的項目主要是用MatLab編寫的,所以我所做的是將ID和TotalParticles數據從數據庫中提取出來,然後在Matlab中對TotalParticles列運行檢查。這個腳本的輸出是我需要用於摺疊數據庫的ID值,我將它提供給一個簡單的select語句,然後這將使我需要的視圖。