MySQL DISTINCT sur un GROUP_CONCAT ()


186

Je fais SELECT GROUP_CONCAT(categories SEPARATOR ' ') FROM table. Exemple de données ci-dessous:

categories
----------
test1 test2 test3
test4
test1 test3
test1 test3

Cependant, je test1 test2 test3 test4 test1 test3reviens et j'aimerais test1 test2 test3 test4revenir. Des idées?

Merci beaucoup!

Réponses:


364

GROUP_CONCAT a l'attribut DISTINCT:

SELECT GROUP_CONCAT(DISTINCT categories ORDER BY categories ASC SEPARATOR ' ') FROM table

48

L'utilisation de DISTINCT fonctionnera

SELECT GROUP_CONCAT(DISTINCT(categories) SEPARATOR ' ') FROM table

REf: - ce


20

DISTINCT: vous donnera des valeurs uniques.

SELECT GROUP_CONCAT(DISTINCT(categories )) AS categories FROM table

17

Les autres réponses à cette question ne retournent pas ce dont l'OP a besoin, elles renverront une chaîne comme:

test1 test2 test3 test1 test3 test4

(notez que test1et test3sont dupliqués) pendant que l'OP veut retourner cette chaîne:

test1 test2 test3 test4

le problème ici est que la chaîne "test1 test3"est dupliquée et n'est insérée qu'une seule fois, mais toutes les autres sont distinctes les unes des autres ( "test1 test2 test3"est distinct de "test1 test3", même si certains tests contenus dans la chaîne entière sont dupliqués).

Ce que nous devons faire ici est de diviser chaque chaîne en différentes lignes, et nous devons d'abord créer une table de nombres:

CREATE TABLE numbers (n INT);
INSERT INTO numbers VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

alors nous pouvons exécuter cette requête:

SELECT
  SUBSTRING_INDEX(
    SUBSTRING_INDEX(tableName.categories, ' ', numbers.n),
    ' ',
    -1) category
FROM
  numbers INNER JOIN tableName
  ON
    LENGTH(tableName.categories)>=
    LENGTH(REPLACE(tableName.categories, ' ', ''))+numbers.n-1;

et nous obtenons un résultat comme celui-ci:

test1
test4
test1
test1
test2
test3
test3
test3

puis nous pouvons appliquer la fonction d'agrégation GROUP_CONCAT, en utilisant la clause DISTINCT:

SELECT
  GROUP_CONCAT(DISTINCT category ORDER BY category SEPARATOR ' ')
FROM (
  SELECT
    SUBSTRING_INDEX(SUBSTRING_INDEX(tableName.categories, ' ', numbers.n), ' ', -1) category
  FROM
    numbers INNER JOIN tableName
    ON LENGTH(tableName.categories)>=LENGTH(REPLACE(tableName.categories, ' ', ''))+numbers.n-1
  ) s;

S'il vous plaît voir violon ici .


Il semble que votre interprétation de la question d'OP soit correcte; cependant, je pense qu'il convient de souligner que normaliser les données en créant un tableau "blah_to_categories" et un tableau "categories" pour la relation plusieurs-à-plusieurs appropriée serait la meilleure pratique ici, et ajouterait beaucoup de flexibilité. Pourtant, votre réponse est une solution de contournement intelligente pour quiconque hérite d'un tel schéma dénormalisé. Il pourrait aussi probablement être adapté dans le but de générer une migration de l'ancien vers le schéma normalisé.
XP84

11
SELECT
  GROUP_CONCAT(DISTINCT (category))
FROM (
  SELECT
    SUBSTRING_INDEX(SUBSTRING_INDEX(tableName.categories, ' ', numbers.n), ' ', -1) category
  FROM
    numbers INNER JOIN tableName
    ON LENGTH(tableName.categories)>=LENGTH(REPLACE(tableName.categories, ' ', ''))+numbers.n-1
  ) s;   

Cela renverra des valeurs distinctes comme: test1, test2, test4, test3


6

Vous pouvez simplement ajouter DISTINCT devant.

SELECT GROUP_CONCAT(DISTINCT categories SEPARATOR ' ')

si vous voulez trier,

SELECT GROUP_CONCAT(DISTINCT categories ORDER BY categories ASC SEPARATOR ' ')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.