2列あります
date number
---- ------
1 3
2 NULL
3 5
4 NULL
5 NULL
6 2
.......
NULL値を新しい値に置き換える必要があります。日付列の前の日付の最後の既知の値から値を取得します。例:date = 2 number = 3、date 4 and 5 number = 5および5。NULL値が表示されます無作為に。
Sql Serverを使用している場合、これは動作するはずです
DECLARE @Table TABLE(
ID INT,
Val INT
)
INSERT INTO @Table (ID,Val) SELECT 1, 3
INSERT INTO @Table (ID,Val) SELECT 2, NULL
INSERT INTO @Table (ID,Val) SELECT 3, 5
INSERT INTO @Table (ID,Val) SELECT 4, NULL
INSERT INTO @Table (ID,Val) SELECT 5, NULL
INSERT INTO @Table (ID,Val) SELECT 6, 2
SELECT *,
ISNULL(Val, (SELECT TOP 1 Val FROM @Table WHERE ID < t.ID AND Val IS NOT NULL ORDER BY ID DESC))
FROM @Table t
MySQLソリューションは次のとおりです。
_UPDATE mytable
SET number = (@n := COALESCE(number, @n))
ORDER BY date;
_
これは簡潔ですが、他のブランドのRDBMSでは必要ありません。他のブランドの場合、より関連性の高いブランド固有のソリューションが存在する場合があります。そのため、使用しているブランドをお知らせください。
@Paxがコメントしたように、ベンダーに依存しないのは良いことですが、それに失敗した場合は、選択したブランドのデータベースを最大限に活用することも良いことです。
上記のクエリの説明:
_@n
_はMySQLユーザー変数です。 NULLから始まり、UPDATEが行を実行するときに各行に値が割り当てられます。 number
がNULLでない場合、_@n
_にはnumber
の値が割り当てられます。 number
がNULLの場合、COALESCE()
はデフォルトの_@n
_の以前の値になります。いずれの場合でも、これはnumber
列の新しい値になり、UPDATEは次の行に進みます。 _@n
_変数は行ごとに値を保持するため、後続の行は前の行からの値を取得します。 MySQLはORDER BYをUPDATEとともに特別に使用しているため、UPDATEの順序は予測可能です(これは標準SQLではありません)。
最良のソリューションは、ビルカーウィンが提供するものです。私は最近、比較的大きな結果セットでこれを解決しなければなりませんでした(各列にこのタイプの「現在の行でこの値がnullの場合、最後の非null値を表示する」を必要とする12列の1000行)とトップ1の更新メソッドを使用して以前の既知の値の選択(または上位1のサブクエリ)が非常に遅く実行されました。
私はSQL 2005を使用していますが、変数置換の構文はmysqlとは少し異なります。
UPDATE mytable
SET
@n = COALESCE(number, @n),
number = COALESCE(number, @n)
ORDER BY date
最初のsetステートメントは、変数@nの値を現在の行の値 'number'に更新します( 'number'がNULLでない場合(COALESCEは、渡された最初の非NULL引数を返します)。2番目のsetステートメントは、実際のそれ自身への 'number'の列値(nullでない場合)または変数@n(常に最後に検出されたNULL以外の値が含まれます)。
このアプローチの利点は、一時テーブルを何度もスキャンするために追加のリソースが消費されないことです... @nの行内更新は、最後の非NULL値の追跡を処理します。
私は彼の答えを投票するのに十分な担当者がいませんが、誰かがそうすべきです。最もエレガントで最高のパフォーマンスを発揮します。
Oracleソリューション(10g以上)は次のとおりです。分析関数last_value()
をignore nulls
オプションと共に使用し、列の最後の非NULL値を置き換えます。
SQL> select *
2 from mytable
3 order by id
4 /
ID SOMECOL
---------- ----------
1 3
2
3 5
4
5
6 2
6 rows selected.
SQL> select id
2 , last_value(somecol ignore nulls) over (order by id) somecol
3 from mytable
4 /
ID SOMECOL
---------- ----------
1 3
2 3
3 5
4 5
5 5
6 2
6 rows selected.
SQL>
次のスクリプトはこの問題を解決し、プレーンなANSI SQLのみを使用します。このソリューションを SQL2008 、 SQLite および Oracle11g でテストしました。
CREATE TABLE test(mysequence INT, mynumber INT);
INSERT INTO test VALUES(1, 3);
INSERT INTO test VALUES(2, NULL);
INSERT INTO test VALUES(3, 5);
INSERT INTO test VALUES(4, NULL);
INSERT INTO test VALUES(5, NULL);
INSERT INTO test VALUES(6, 2);
SELECT t1.mysequence, t1.mynumber AS ORIGINAL
, (
SELECT t2.mynumber
FROM test t2
WHERE t2.mysequence = (
SELECT MAX(t3.mysequence)
FROM test t3
WHERE t3.mysequence <= t1.mysequence
AND mynumber IS NOT NULL
)
) AS CALCULATED
FROM test t1;
私はそれが非常に古いフォーラムであることを知っていますが、私の問題のトラブルシューティング中にこれに遭遇しました:)ちょうど他の人が上記の問題に少し複雑な解決策を与えていることに気付きました。以下の私の解決策をご覧ください:
DECLARE @A TABLE(ID INT, Val INT)
INSERT INTO @A(ID,Val) SELECT 1, 3
INSERT INTO @A(ID,Val) SELECT 2, NULL
INSERT INTO @A(ID,Val) SELECT 3, 5
INSERT INTO @A(ID,Val) SELECT 4, NULL
INSERT INTO @A(ID,Val) SELECT 5, NULL
INSERT INTO @A(ID,Val) SELECT 6, 2
UPDATE D
SET D.VAL = E.VAL
FROM (SELECT A.ID C_ID, MAX(B.ID) P_ID
FROM @A AS A
JOIN @A AS B ON A.ID > B.ID
WHERE A.Val IS NULL
AND B.Val IS NOT NULL
GROUP BY A.ID) AS C
JOIN @A AS D ON C.C_ID = D.ID
JOIN @A AS E ON C.P_ID = E.ID
SELECT * FROM @A
これが誰かを助けることを願っています:)
Redshiftのソリューションを探している場合、これはframe節で機能します:
SELECT date,
last_value(columnName ignore nulls)
over (order by date
rows between unbounded preceding and current row) as columnName
from tbl
非常に一般的な意味で:
UPDATE MyTable
SET MyNullValue = MyDate
WHERE MyNullValue IS NULL
これがMS Accessのソリューションです。
例のテーブルはtab
と呼ばれ、フィールドはid
とval
です。
SELECT (SELECT last(val)
FROM tab AS temp
WHERE tab.id >= temp.id AND temp.val IS NOT NULL) AS val2, *
FROM tab;
まず、本当に値を保存する必要がありますか?あなたは仕事をするビューを使用するだけです:
_SELECT t."date",
x."number" AS "number"
FROM @Table t
JOIN @Table x
ON x."date" = (SELECT TOP 1 z."date"
FROM @Table z
WHERE z."date" <= t."date"
AND z."number" IS NOT NULL
ORDER BY z."date" DESC)
_
本当にID ("date")
列があり、それが(クラスター化された)主キーである場合、このクエリはかなり高速です。ただし、クエリプランを確認してください。Val
列を含むカバーインデックスを用意することをお勧めします。
また、プロシージャを避けることができるときにプロシージャが気に入らない場合は、UPDATE
に対して同様のクエリを使用することもできます。
_UPDATE t
SET t."number" = x."number"
FROM @Table t
JOIN @Table x
ON x."date" = (SELECT TOP 1 z."date"
FROM @Table z
WHERE z."date" < t."date" --//@note: < and not <= here, as = not required
AND z."number" IS NOT NULL
ORDER BY z."date" DESC)
WHERE t."number" IS NULL
_
注:コードは「SQL Server」で動作する必要があります。
UPDATE TABLE
SET number = (SELECT MAX(t.number)
FROM TABLE t
WHERE t.number IS NOT NULL
AND t.date < date)
WHERE number IS NULL