web-dev-qa-db-fra.com

GROUP BY - ne pas grouper NULL

J'essaie de trouver un moyen de retourner les résultats en utilisant la fonction group by.

GROUP BY fonctionne comme prévu, mais ma question est la suivante: est-il possible d'avoir un groupe en ignorant le champ NULL. De sorte qu'il ne regroupe pas les NULL ensemble car j'ai toujours besoin de toutes les lignes où le champ spécifié est NULL.

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

Alors maintenant, disons que j'ai 5 lignes et que le champ ancêtre est NULL, il me renvoie 1 ligne .... mais je veux les 5.

59
slik

Peut-être devriez-vous ajouter quelque chose aux colonnes nulles pour les rendre uniques et les regrouper? Je cherchais une sorte de séquence à utiliser à la place de UUID () mais cela pourrait aussi bien fonctionner.

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

Lors du regroupement par colonne Y, toutes les lignes pour lesquelles la valeur dans Y est NULL sont regroupées.

Ce comportement est défini par la norme SQL-20 , bien que cela soit légèrement surprenant car NULL n'est pas égal à NULL.

Vous pouvez contourner ce problème en regroupant sur une valeur différente, une fonction (mathématiquement parlant) des données de votre colonne de regroupement.

Si vous avez une colonne unique X, c'est facile.


Contribution

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

Sans correctif

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

Résultat:

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

Avec correctif

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

Résultat:

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

Examinons de plus près comment cela fonctionne

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

Résultat:

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

Si vous ne disposez pas d'une colonne unique que vous pouvez utiliser, vous pouvez essayer de générer une valeur d'espace réservé unique à la place. Je vais laisser cela comme un exercice au lecteur.

37

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ᵀᴹ

Peut-être une version plus rapide de la solution précédente au cas où vous avez un identifiant unique dans table1 (supposons que ce soit 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