112 votes

Valeurs SQL divisées en plusieurs lignes

J'ai une table :

id | name    
1  | a,b,c    
2  | b

Je veux une sortie comme celle-ci :

id | name    
1  | a    
1  | b    
1  | c    
2  | b

1voto

Imanez Points 492
CREATE PROCEDURE `getVal`()
BEGIN
        declare r_len integer;
        declare r_id integer;
        declare r_val varchar(20);
        declare i integer;
        DECLARE found_row int(10);
        DECLARE row CURSOR FOR select length(replace(val,"|","")),id,val from split;
        create table x(id int,name varchar(20));
      open row;
            select FOUND_ROWS() into found_row ;
            read_loop: LOOP
                IF found_row = 0 THEN
                         LEAVE read_loop;
                END IF;
            set i = 1;  
            FETCH row INTO r_len,r_id,r_val;
            label1: LOOP        
                IF i <= r_len THEN
                  insert into x values( r_id,SUBSTRING(replace(r_val,"|",""),i,1));
                  SET i = i + 1;
                  ITERATE label1;
                END IF;
                LEAVE label1;
            END LOOP label1;
            set found_row = found_row - 1;
            END LOOP;
        close row;
        select * from x;
        drop table x;
END

1voto

user9526573 Points 33

La question initiale concernait MySQL et SQL en général. L'exemple ci-dessous concerne les nouvelles versions de MySQL. Malheureusement, une requête générique qui fonctionnerait sur n'importe quel serveur SQL n'est pas possible. Certains serveurs ne supportent pas CTE, d'autres n'ont pas substring_index, d'autres encore ont des fonctions intégrées pour diviser une chaîne en plusieurs lignes.

--- la réponse suit ---

Les requêtes récursives sont pratiques lorsque le serveur ne fournit pas de fonctionnalité intégrée. Elles peuvent également constituer un goulot d'étranglement.

La requête suivante a été écrite et testée sur la version 8.0.16 de MySQL. Elle ne fonctionnera pas sur la version 5.7-. Les anciennes versions ne supportent pas le Common Table Expression (CTE) et donc les requêtes récursives.

with recursive
  input as (
        select 1 as id, 'a,b,c' as names
      union
        select 2, 'b'
    ),
  recurs as (
        select id, 1 as pos, names as remain, substring_index( names, ',', 1 ) as name
          from input
      union all
        select id, pos + 1, substring( remain, char_length( name ) + 2 ),
            substring_index( substring( remain, char_length( name ) + 2 ), ',', 1 )
          from recurs
          where char_length( remain ) > char_length( name )
    )
select id, name
  from recurs
  order by id, pos;

0voto

qupc Points 1

Meilleure pratique. Résultat :

SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX('ab,bc,cd',',',help_id+1),',',-1) AS oid
FROM
(
SELECT @xi:=@xi+1 as help_id from 
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc2,
(SELECT @xi:=-1) xc0
) a
WHERE 
help_id < LENGTH('ab,bc,cd')-LENGTH(REPLACE('ab,bc,cd',',',''))+1

Tout d'abord, créez un tableau de chiffres :

SELECT @xi:=@xi+1 as help_id from 
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) xc2,
(SELECT @xi:=-1) xc0;

| help_id  |
| --- |
| 0   |
| 1   |
| 2   |
| 3   |
| ...   |
| 24   |

Deuxièmement, il suffit de diviser la branche :

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('ab,bc,cd',',',help_id+1),',',-1) AS oid
FROM
numbers_table
WHERE
help_id < LENGTH('ab,bc,cd')-LENGTH(REPLACE('ab,bc,cd',',',''))+1

| oid  |
| --- |
| ab   |
| bc   |
| cd   |

-1voto

Voici ma solution

-- Create the maximum number of words we want to pick (indexes in n)
with recursive n(i) as (
    select
        1 i
    union all
    select i+1 from n where i < 1000
)
select distinct
    s.id,
    s.oaddress,
    -- n.i,
    -- use the index to pick the nth word, the last words will always repeat. Remove the duplicates with distinct
    if(instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' ') > 0,
        reverse(substr(reverse(trim(substring_index(s.oaddress,' ',n.i))),1,
            instr(reverse(trim(substring_index(s.oaddress,' ',n.i))),' '))),
        trim(substring_index(s.oaddress,' ',n.i))) oth
from 
    app_schools s,
    n

-4voto

Trace Ashley Points 19
SELECT id, unnest(string_to_array(name, ',')) AS names
FROM datatable

J'espère que cela vous aidera :D

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X