2015-04-29 14 views
9

Ho 3 tabelle mysql (animale, categoria e animale_2_categoria). Ogni animale può avere categorie 0-n (ad esempio pesce, animale domestico, insetto, carnivoro, "può volare", ecc.).Mysql ordinamento valori concatenati

Tabella "animale" (id, nome)

1, dog 
2, cat 
3, bee 
... 

tabella "categorie" (id, nome)

1, pet 
2, insect 
3, mammal 
4, fish 
5, can fly 
... 

Tabella "animal_2_category" (animal_id, category_id)

1, 1 
1, 3 
2, 1 
2, 3 
3, 2 
3, 5 
... 

Ciò di cui ho bisogno ora è un elenco di tutte le combinazioni di categorie. La seguente query funziona:

SELECT CONCAT_WS("-", x.name, c.name) 
FROM animal_2_category a2c1 
    JOIN animal_2_category a2c2 ON a2c1.animal_id = a2c2.animal_id 
    JOIN category c ON c.id = a2c2.category_id´ 
    JOIN categories x 
GROUP BY a2c2.category_id 

Questa query wil restituire i seguenti:

  • pet-mammifero
  • mammifero-pet
  • insetti possono volare

Il problema con questo, ricevo voci pubblicitarie "pet-mammal" e "mammal-pet". Come posso modificare la query, per ottenere solo uno di loro, per esempio:

  • pet-mammifero
  • insetti possono volare
+0

Bellissima domanda –

+0

Non c'è bisogno per concatenare questi dati. In realtà, per approssimazione approssimativa, non c'è alcun problema in SQL per il quale CONCAT o GROUP_CONCAT devono essere parte della risposta. – Strawberry

+0

Basta aggiungere un requisito che l'ID di un risultato deve essere inferiore all'ID dell'altro risultato. – Strawberry

risposta

2

È inoltre possibile riscrivere la query come

SELECT DISTINCT GREATEST(CONCAT_WS("-", x.name, c.name),CONCAT_WS("-", c.name, x.name)) col 
FROM animal_2_category a2c1 
    JOIN animal_2_category a2c2 ON a2c1.animal_id = a2c2.animal_id 
    JOIN categories c ON c.id = a2c2.`category_id` 
    JOIN categories `x` ON a2c1.category_id = x.id 
    WHERE x.name <> c.name 

DEMO

1

Un modo per evitare coppie duplicati è quello di garantire la vostra le coppie vengono sempre create nello stesso ordine. Possiamo farlo assemblando la tua coppia in una dichiarazione if, che ordina in modo efficace i due valori per noi. Quindi prendiamo semplicemente le righe distinte.

select distinct if(c1.name > c2.name, concat_ws('-', c1.name, c2.name), concat_ws('-', c2.name, c1.name)) pairing 
    from animal_2_category a1 
    inner join animal_2_category a2 
     on a1.animal_id = a2.animal_id 
     and a1.category_id <> a2.category_id 
    inner join categories c1 
     on a1.category_id = c1.id 
    inner join categories c2 
     on a2.category_id = c2.id; 

alternativa, solo essere più selettivi nei criteri di join, quindi si uniscono solo in un particolare ordine. Questo evita il se, ma abbiamo ancora bisogno di afferrare i valori distinti.

select distinct concat_ws('-', c1.name, c2.name) pairing 
    from animal_2_category a1 
    inner join animal_2_category a2 
     on a1.animal_id = a2.animal_id 
     and a1.category_id < a2.category_id 
    inner join categories c1 
     on a1.category_id = c1.id 
    inner join categories c2 
     on a2.category_id = c2.id; 

demo here

In entrambi i casi, i risultati sono gli stessi.

1
SELECT DISTINCT combos 
FROM (
    SELECT animal_id 
    , GROUP_CONCAT(c.name ORDER BY c.name SERPERATOR '-') AS combos 
    FROM animal_2_category a2c 
    JOIN category c ON c.id = a2c.category_id 
    GROUP BY animal_id 
) AS ilv 
+0

questo va bene se vuole che appaiano singole categorie e abbinamenti di categorie, altrimenti ha bisogno di un po 'di amore. –