2013-06-25 23 views
20

mi sembra di venire contro questo problema molto, dove ho dati che sono formattati in questo modo:"Reverse GROUP_CONCAT" in MySQL?

+----+----------------------+ 
| id | colors    | 
+----+----------------------+ 
| 1 | Red,Green,Blue  | 
| 2 | Orangered,Periwinkle | 
+----+----------------------+ 

ma io vorrei formattato in questo modo:

+----+------------+ 
| id | colors  | 
+----+------------+ 
| 1 | Red  | 
| 1 | Green  | 
| 1 | Blue  | 
| 2 | Orangered | 
| 2 | Periwinkle | 
+----+------------+ 

C'è un buon modo per farlo Questo? Come viene chiamato questo tipo di operazione?

+1

Tale operazione si chiama rotazione/unpivoting – nothrow

+0

Impressionante, grazie –

risposta

7

penso che sia quello che vi serve (stored procedure): Mysql split column string into rows

DELIMITER $$ 

DROP PROCEDURE IF EXISTS explode_table $$ 
CREATE PROCEDURE explode_table(bound VARCHAR(255)) 

BEGIN 

DECLARE id INT DEFAULT 0; 
DECLARE value TEXT; 
DECLARE occurance INT DEFAULT 0; 
DECLARE i INT DEFAULT 0; 
DECLARE splitted_value INT; 
DECLARE done INT DEFAULT 0; 
DECLARE cur1 CURSOR FOR SELECT table1.id, table1.value 
            FROM table1 
            WHERE table1.value != ''; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

DROP TEMPORARY TABLE IF EXISTS table2; 
CREATE TEMPORARY TABLE table2(
`id` INT NOT NULL, 
`value` VARCHAR(255) NOT NULL 
) ENGINE=Memory; 

OPEN cur1; 
    read_loop: LOOP 
    FETCH cur1 INTO id, value; 
    IF done THEN 
     LEAVE read_loop; 
    END IF; 

    SET occurance = (SELECT LENGTH(value) 
          - LENGTH(REPLACE(value, bound, '')) 
          +1); 
    SET i=1; 
    WHILE i <= occurance DO 
     SET splitted_value = 
     (SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(value, bound, i), 
     LENGTH(SUBSTRING_INDEX(value, bound, i - 1)) + 1), ',', '')); 

     INSERT INTO table2 VALUES (id, splitted_value); 
     SET i = i + 1; 

    END WHILE; 
    END LOOP; 

    SELECT * FROM table2; 
CLOSE cur1; 
END; $$ 
+0

Fantastico, questo è esattamente quello che stavo cercando –

+0

Superbo !!! Tu sei un uomo!!! : D –

+1

@kmas, cosa significa "procedura disponibile"? – Pacerier

10

si potrebbe usare una query come questa:

SELECT 
    id, 
    SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color 
FROM 
    colors 
    INNER JOIN 
    (SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) n 
    ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit 
ORDER BY 
    id, 
    n.digit 

Vedere violino here. Si prega di notare che questa query supporterà fino a 4 colori per ogni riga, è necessario aggiornare la sottoquery per restituire più di 4 numeri (o si dovrebbe usare una tabella che contiene 10 o 100 numeri).

+0

Questo non è proprio quello che sto cercando, ero più alla ricerca di qualcosa che può gestire N file per ID. Grazie però :) –

+0

@JasonHamje se hai bisogno di usare una query e non una stored procedure, non c'è altro modo :) – fthiella

+0

Gotcha, grazie –

0

Questo mi ha salvato molte ore! Andando oltre: su un'implementazione tipica ci sarebbe probabilmente una tabella che enumera i colori rispetto a una chiave identitaria, color_list. Un nuovo colore può essere aggiunto alla attuazione senza dover modificare la query e potenzialmente infinita union -clause può essere evitata del tutto cambiando l'interrogazione a questo:

SELECT id, 
    SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color 
FROM 
    colors 
    INNER JOIN 
    (select id as digit from color_list) n 
    ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit 
ORDER BY id, n.digit; 

È importante che gli ID nella tabella color_list rimangono sequenziale, comunque.

0

avviso questo può essere fatto senza creare una tabella temporanea

select id, substring_index(substring_index(genre, ',', n), ',', -1) as genre 
from my_table 
join 
(SELECT @row := @row + 1 as n FROM 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t, 
(SELECT @row:=0) r) as numbers 
    on char_length(genre) 
    - char_length(replace(genre, ',', '')) >= n - 1 
+0

puoi anche contare e raggruppare se vuoi –