7

次のスキーマを持つテーブルがあります。

DateTime [Creation Date] PK
int [Data]

列データには、次のようなセンサーからの値が含まれています。

123
225
354
578
0
2151
2331
0
2555
2678

ご覧のとおり、値は常に増加します。

センサーの問題により、有効な値の間に 0 が表示されることがあります。これにより、データを使用しようとするといくつかの問題が発生するため、これらの 0 のギャップを何かで埋めたいと考えています。理想的には、前の値と次の値の間に平均を置きたいと考えています。これが不可能な場合は、前の値を繰り返したいと考えています。

これはクエリだけで実行できますか?

前もって感謝します。

4

4 に答える 4

3

おそらく最も効率的なものではないかもしれませんが、うまくいくはずです:

WITH cte 
     AS (SELECT [Creation Date], 
                Data, 
                rn=Row_number() OVER(ORDER BY [Creation Date]) 
         FROM   dbo.Table) 
UPDATE cte 
SET    Data = ( ( (SELECT c2.Data
                    FROM   cte c2 
                    WHERE  c2.rn = cte.rn - 1) 
                   + (SELECT c2.Data
                      FROM   cte c2 
                      WHERE  c2.rn = cte.rn + 1) ) / 2 ) 
WHERE  Data = 0;

CTE で使用Row_Numberして、 で並べ替えられた連続番号を取得しCreation Dateます。次に、この数値を使用して、前の値と次の値に従って新しいデータを取得します。

同様のスキーマを使用したデモを次に示しintます (私は の代わりに を使用しましたdatetime):

アップデート

いいものですが、複数の 0 のギャップを処理しません

良いキャッチです。これを考慮して変更されたSQLは次のとおりです。

WITH cte 
     AS (SELECT [Creation Date], 
                Data, 
                rn=Row_number() OVER(ORDER BY [Creation Date]) 
         FROM   dbo.Table) 
UPDATE cte 
SET    Data = ( ( (SELECT c2.Data
                    FROM   cte c2 
                    WHERE  c2.rn = (SELECT MAX(RN)FROM CTE c3 WHERE c3.RN<cte.RN AND c3.Data<>0)) 
                   + (SELECT c2.Data
                      FROM   cte c2 
                      WHERE  c2.rn = (SELECT MIN(RN)FROM CTE c3 WHERE c3.RN>cte.RN AND c3.Data<>0))) / 2 ) 
WHERE  Data = 0;

デモ(5,6 にゼロが連続)

于 2013-02-26T11:23:24.390 に答える
1

別のバリエーションがあります:

SELECT 
BadDate, 
T1.Data AS PrevData, 
T2.Data AS NextData,
(T1.Data + T2.Data) / 2 AS AvgValue
FROM

(

SELECT 
T1.CreationDate As BadDate, 
Max(T2.CreationDate) As PrevDate,
Min(T3.CreationDate) As NextDate

FROM 
TestData T1, 
TestData T2,
TestData T3

WHERE 

T1.Data = 0
AND T2.Data <> 0
AND T2.CreationDate < T1.CreationDate
AND T3.Data <> 0
AND T3.CreationDate > T1.CreationDate

GROUP BY T1.CreationDate

) DateData

INNER JOIN TestData T1
ON DateData.PrevDate = T1.CreationDate

INNER JOIN TestData T2
ON DateData.NextDate = T2.CreationDate
于 2013-02-26T11:24:12.210 に答える
0

もう1つのオプション

UPDATE s
SET s.Data = (COALESCE(o1.Data, o2.Data) + COALESCE(o2.Data, o1.Data)) / 2
FROM dbo.sensor s OUTER APPLY (
                               SELECT TOP 1 s2.Data AS Data
                               FROM dbo.sensor s2
                               WHERE s2.Data != 0 AND s.[Creation Date] < s2.[Creation Date]
                               ORDER BY s2.[Creation Date] ASC                         
                               ) o1
                  OUTER APPLY (
                               SELECT TOP 1 s3.Data AS Data
                               FROM dbo.sensor s3
                               WHERE s3.Data != 0 AND s.[Creation Date] > s3.[Creation Date]                               
                               ORDER BY s3.[Creation Date] DESC 
                               ) o2
WHERE s.Data = 0     

SQLFiddleのデモ

于 2013-02-26T11:46:38.587 に答える
0

平均を取得することを心配しない場合、このメソッドは前の値に数値を追加できます。

また、この方法に(すべてのレコードを更新する以外に)問題があるかどうかはわかりませんが、単に別の単純なアプローチとして示されているだけであることに注意してください...

declare @new int = 1

update mytable
set @new  = val  = case when val = 0 then @new + 1 else val end

フィドルのデモ

|          D |  VAL |
---------------------
| 2013-01-01 |  123 |
| 2013-01-02 |  225 |
| 2013-01-03 |  354 |
| 2013-01-04 |  578 |
| 2013-01-05 |  579 |--Updated
| 2013-01-06 | 2151 |
| 2013-01-07 | 2331 |
| 2013-01-08 | 2332 |--Updated
| 2013-01-09 | 2555 |
| 2013-01-10 | 2678 |
于 2013-02-26T11:39:25.097 に答える