SQL split values to multiple rows

前端 未结 9 1417
刺人心
刺人心 2020-11-21 05:28

I have table :

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

i want output like this :

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


        
相关标签:
9条回答
  • 2020-11-21 05:49
    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
    
    0 讨论(0)
  • 2020-11-21 05:57

    Best Practice. Result:

    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
    

    First, create a numbers table:

    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   |
    

    Second, just split the str:

    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   |
    
    0 讨论(0)
  • 2020-11-21 05:59

    The original question was for MySQL and SQL in general. The example below is for the new versions of MySQL. Unfortunately, a generic query that would work on any SQL server is not possible. Some servers do no support CTE, others do not have substring_index, yet others have built-in functions for splitting a string into multiple rows.

    --- the answer follows ---

    Recursive queries are convenient when the server does not provide built-in functionality. They can also be the bottleneck.

    The following query was written and tested on MySQL version 8.0.16. It will not work on version 5.7-. The old versions do not support Common Table Expression (CTE) and thus recursive queries.

    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;
    
    0 讨论(0)
提交回复
热议问题