web-dev-qa-db-ja.com

GROUP BY-NULLをグループ化しない

Group by関数を使用して結果を返す方法を見つけようとしています。

GROUP BYは期待どおりに機能していますが、私の質問は次のとおりです。NULLフィールドを無視してグループ化することは可能ですか。指定されたフィールドがNULLであるすべての行が必要なため、NULLをグループ化しないようにします。

SELECT `table1`.*, 
    GROUP_CONCAT(id SEPARATOR ',') AS `children_ids`
FROM `table1` 
WHERE (enabled = 1) 
GROUP BY `ancestor` 

だから今私は5行を持っていて、祖先フィールドがNULLであると言うことができます、それは私に1行を返します....しかし、私はすべて5が欲しいです。

59
slik

おそらく、null列に何かを追加して、それらを一意にしてグループ化する必要がありますか? UUID()の代わりに使用する何らかのシーケンスを探していましたが、これも同様に機能する可能性があります。

SELECT `table1`.*, 
    IFNULL(ancestor,UUID()) as unq_ancestor
    GROUP_CONCAT(id SEPARATOR ',') AS `children_ids`
FROM `table1` 
WHERE (enabled = 1) 
GROUP BY unq_ancestor
58
bot403

Yでグループ化すると、Yの値がNULLであるすべての行がグループ化されます。

この動作はSQL-2003標準で定義されています 。ただし、NULLNULLと等しくないため、少し驚きです。

別の値、グループ化列のデータの一部function(数学的に言えば)でグループ化することで回避できます。

一意の列Xがある場合、これは簡単です。


入力

X      Y
-------------
1      a
2      a
3      b
4      b
5      c
6      (NULL)
7      (NULL)
8      d

修正なし

SELECT GROUP_CONCAT(`X`)
  FROM `tbl`
 GROUP BY `Y`;

結果:

GROUP_CONCAT(`foo`)
-------------------
6,7
1,2
3,4
5
8

修正あり

SELECT GROUP_CONCAT(`X`)
  FROM `tbl`
 GROUP BY IFNULL(`Y`, `X`);

結果:

GROUP_CONCAT(`foo`)
-------------------
6
7
1,2
3,4
5
8

これがどのように機能しているかを詳しく見てみましょう

SELECT GROUP_CONCAT(`X`), IFNULL(`Y`, `X`) AS `grp`
  FROM `tbl`
 GROUP BY `grp`;

結果:

GROUP_CONCAT(`foo`)     `grp`
-----------------------------
6                       6
7                       7
1,2                     a
3,4                     b
5                       c
8                       d

使用できる一意の列がない場合は、代わりに一意のプレースホルダー値を生成してみてください。これは読者への演習として残しておきます。

GROUP BY IFNULL(required_field, id)

21
Hett
SELECT table1.*, 
    GROUP_CONCAT(id SEPARATOR ',') AS children_ids
FROM table1
WHERE (enabled = 1) 
GROUP BY ancestor
       , CASE WHEN ancestor IS NULL
                  THEN table1.id
                  ELSE 0
         END
9
ypercubeᵀᴹ

Table1に一意の識別子がある場合の以前のソリューションの高速バージョンかもしれません(table1.idとします):

SELECT `table1`.*, 
    GROUP_CONCAT(id SEPARATOR ',') AS `children_ids`,
    IF(ISNULL(ancestor),table1.id,NULL) as `do_not_group_on_null_ancestor`
FROM `table1` 
WHERE (enabled = 1) 
GROUP BY `ancestor`, `do_not_group_on_null_ancestor`
6
Stepan