2016-12-11 2 views
1

問題:ここCOALESCE関数は

CREATE TABLE Score(`id` int, `col1` INT NULL); 
INSERT INTO Score 
    (`id`, `col1`) 
VALUES 
    (2, NULL), 
    (3, 10), 
    (5, -1), 
    (7, NULL), 
    (11, NULL), 
    (13, -12), 
    (17, NULL), 
    (19, NULL), 
    (23, 1759); 
http://sqlmag.com/t-sql/last-non-null-puzzleを発見し、ID順に基づいてテーブルから最後の非NULL値を見つけることです

所望の出力:SQLFiddleで

id          col1        lastval 
----------- ----------- ----------- 
2           NULL        NULL 
3           10          10 
5           -1          -1 
7           NULL        -1 
11          NULL        -1 
13          -12         -12 
17          NULL        -12 
19          NULL        -12 
23          1759        1759 

マイコードMySQL 5.6

SELECT s1.id, COALESCE(s2.col1) 
FROM score s1 JOIN score s2 
ON s1.id >= s2.id 
GROUP BY s1.id 
ORDER BY s1.id, s2.id DESC 

私が理解しているように、最初の非NULL値はリスト。しかし、それはすべての列に(null)を与えています。 COALESCEが動作しない理由を指摘できますか? また、COALESCEを削除すると、GROUP BY句がs2.col1列の最初の値を返すという質問にも答える必要があります。私はここで間違っているかもしれない。

答えて

2

COALESCEを助けた引数のリストで最初の非NULL値を返します願っています。グループ化された行セットに対してCOALESCE()を同じ式に適用する暗黙の動作はありません。 SUM()やGROUP_CONCAT()のような集約関数ではありません。

1つの引数を与えただけなので、1つの引数で使用することは意味がありません。だから、s2.col1をクエリの選択リストに入れてCOALESCE()呼び出しの中に入れることとまったく同じです。

GROUP BY関数でグループ化されていない列を参照するとき、MySQLのデフォルトの動作が残っています。MySQLはグループ内のある行から任意にs2.col1という値を選択します。実際には、これはインデックス順序で読み込まれたグループの最初の行ですが、これに依存するべきではありません。

あなたの例では、すべての行s1とすべての行が結合されます。のように、s2.idが先です。すべてのグループにテーブルの最初の行が含まれます。s2.id=2。そしてその行はcol1のためのNULLを持っています。

解決しようとしているSQLパズルを読みました。 MySQLはウィンドウ関数をサポートしていないので、MySQLでは特に扱いにくいでしょう。

これらの場合の解決策は通常、クエリがテーブルの行を反復処理する際に値を変更するMySQL User-Defined Variablesを使用することです。これはかなり難しいことがあります。ここで


は、私は(無MySQLのユーザー変数を持つ)移植可能な方法で問題を解決する方法は次のとおりです。

SELECT s1.id, s1.col1, s2.col1 as lastval 
FROM Score AS s1 
LEFT OUTER JOIN Score AS s2 ON s2.id <= s1.id AND s2.col1 IS NOT NULL 
LEFT OUTER JOIN Score AS s3 ON s3.id > s2.id AND s3.id <= s1.id AND s3.col1 IS NOT NULL 
WHERE s3.id IS NULL 
ORDER BY s1.id; 

ここに1つは、MySQLユーザー変数を使用して、それを解決できる方法は次のとおりです。

SELECT id, col1, @lastval := COALESCE(col1, @lastval) AS lastval 
FROM (SELECT @lastval := NULL) AS _init 
CROSS JOIN Score 
ORDER BY id; 

相関サブクエリを使用しているため、あなたのコメントにあなたが投稿したクエリは避けています。相関サブクエリは、通常、パフォーマンスが悪いです。

+0

私はSQLでユーザ定義の変数に慣れていません。しかし、私は解決策を見つけました。これが動作するかどうかを確認できますか?'SELECT s1.id、(SELECT s2.col1 FROM score s2 WHERE s2.id <= s1.id およびs2.col1はNULLではありません ORDER BY s2.id DESC LIMIT 1) AS値 スコアから1 ORDER BY s1.id' –

+0

2番目のクエリは、MySQLのユーザー変数を使用して説明してください。 –

0

私はあなたが何をするのか正確には分かりませんでした。また、mysqlでもうまくいくとは思いませんが、これはtsqlで動作します。私はそれが()

SELECT s1.id, COALESCE(min(s2.col1),0) FROM score s1 
    JOIN score s2 ON s1.id >= s2.id GROUP BY s1.id 
    ORDER BY s1.id, min(s2.col1) DESC 
+0

[質問](http://sqlmag.com/t-sql/last-non-null-puzzle)のリンクを参照してください。あなたはなぜこの 'COALESCE(min(s2.col1)、0)'をしたのか説明できますか?これはどのように機能しますか? –

+0

あなたの出力は望みのものではありません。私はより明確に質問を編集しました。 –

+0

私はsum(a)/ sum(b)を持っている場合、例えば、coalesce()でnullを扱うことができます。私はあなたにもう一度質問して、あなたがしたいことを理解しようとしています –