2010-06-21 10 views
122

Je fais SELECT GROUP_CONCAT(categories SEPARATOR ' ') FROM table. Les données d'échantillon ci-dessous:MySQL DISTINCT sur un GROUP_CONCAT()

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

Cependant, je reçois test1 test2 test3 test4 test1 test3 retour et je voudrais obtenir test1 test2 test3 test4 retour. Des idées?

Merci beaucoup!

Répondre

259

GROUP_CONCAT a attribut DISTINCT:

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

L'utilisation DISTINCT travaillera

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

Rèf: - this

16

D'autres réponses à cette question ne retournez pas ce que les besoins OP, ils seront Renvoie une chaîne comme:

test1 test2 test3 test1 test3 test4 

(notez que test1 et test3 sont dupliquées) tandis 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é et est insérée une seule fois, mais tous les autres sont distincts les uns 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 avons d'abord besoin de 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 ceci:

test1 
test4 
test1 
test1 
test2 
test3 
test3 
test3 

puis nous pouvons appliquer la fonction d'agrégation GROUP_CONCAT, nous ing 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 here.

+0

Il semble que votre interprétation de la question de OP puisse être juste; cependant, je pense qu'il convient de souligner que la normalisation des données en créant une table "blah_to_categories" et une table "categories" pour la relation many-to-many 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 également être adapté dans le but de générer une migration de l'ancien vers le schéma normalisé. – XP84

6
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; 

Ceci renvoie des valeurs distinctes comme: test1, test2, test4, test3

1

Je me rends compte de cette question est vieux, mais je me sens comme cela devrait être mentionné: group_concat killer distinct = performance. Si vous travaillez dans de petites bases de données, vous ne le remarquerez pas, mais quand il évolue, cela ne fonctionnera pas très bien.

+1

Je travaille avec une table de 10 millions de lignes et ma requête prend le même temps avec ou sans DISTINCT. J'utilise InnoDB. – ashishduh

+0

Quel type de données? Combien de colonnes? Dans ma base de données, il est lourd sur les grands champs de texte et il y a environ 30 colonnes bizarres utilisant distinct. Enlever seul distinct accélère considérablement, et il utilise Innodb. – photocode

Questions connexes