MySQL拆分列值用于子查询?

时间:2015-04-10 15:32:34

标签: mysql

我正在使用OpenCart插件,它将多个id组合成一个字符串并将它们存储在一个列中。示例值为217606772:15499:15497。连接ID的数量范围为1到5(大多数是两个或三个ID)。

我希望在查询结果中获取这些ID的名称值,并按照与存储ID相同的顺序连接。

为了简单起见,假设这两个表只有两列(实际上有一个我想要连接的第三个表,但这与直接问题无关):

a

|id    | name        |
|6773  | Google      |
|15497 | Apple       |
|15500 | Microsoft   |
|...   | ...         |

b

|id    | var                 |
|123   | 6773:15500:15497    |
|543   | 45688               |
|22311 | 885:2588            |
|...   | ...                 |

基于var 6773:15500:15497我希望查询的输出为Google:Microsoft:Apple

我不知道从哪种查询开始。

3 个答案:

答案 0 :(得分:3)

以这种方式保存数据不是一个好主意。

我想到的第一个想法是:http://sqlfiddle.com/#!2/1dd77/4

SELECT b.*, GROUP_CONCAT(a.name SEPARATOR ':')
FROM table2 as b
LEFT JOIN table1 as a
on b.var = a.id 
  OR  b.var regexp(CONCAT('^',a.id,':'))
  OR  b.var regexp(CONCAT(':',a.id,':'))
  OR  b.var regexp(CONCAT(':',a.id,'$'))
 GROUP BY b.id

编辑1

有序变体:http://sqlfiddle.com/#!2/1dd77/38

SELECT b.*, GROUP_CONCAT(a.name ORDER BY FIND_IN_SET(a.id, REPLACE(b.var,":",",")) SEPARATOR ':' )
FROM table2 as b
LEFT JOIN table1 as a
on b.var = a.id 
  OR  b.var regexp(CONCAT('^',a.id,':'))
  OR  b.var regexp(CONCAT(':',a.id,':'))
  OR  b.var regexp(CONCAT(':',a.id,'$'))
 GROUP BY b.id

答案 1 :(得分:1)

你可以尝试做一个程序。 首先检查分隔符分隔的字符串数。 然后,根据其位置拆分它们的值。 然后,将值存储到变量中。 最后,进行所需的选择并将其返回。

DELIMITER $$
    CREATE PROCEDURE SPLIT_STR_AND_RETURN(str VARCHAR(255) IN, delimiter VARCHAR(12) IN)
    BEGIN
    -- DEFINE MY VARIABLES
    DEFINE v_count_str INT;
    DEFINE v_index INT DEFAULT 1;
    DEFINE v_id_target CHAR(60);
    DEFINE v_name TEXT;

    -- CREATE A TABLE WHERE I STORE THE VALUES
    DROP TEMPORARY TABLE IF EXISTS stored_values_tmp; -- make sure it doesnt already exist
    CREATE TEMPORARY TABLE stored_values_tmp (
      name_str varchar(120)
    ) ENGINE=memory;

    -- GET HOW MANY IDs I HAVE
    SELECT (LENGTH( str ) - LENGTH( REPLACE( str, delimiter,  '' ) ))+1 INTO v_count_str;
    -- DO A LOOP FOR OBTAINT THE IDs. POSITION = index
    WHILE v_index <= v_count_str DO
      -- SPLIT THE STRING
      SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(str, delimiter, v_index),
           LENGTH(SUBSTRING_INDEX(str, delimiter, v_index -1)) + 1),
           delimiter, '') INTO v_id_target;
      -- GET THE NAME
      SELECT name INTO v_name FROM table_a WHERE id = v_id_target
      -- STORE
      INSERT INTO stored_values_tmp(name_str) VALUES(v_name);
    END WHILE;

    -- GET THE RESULT
    SELECT * FROM stored_values_tmp;

    -- DROP TMP TABLE
    DROP TEMPORARY TABLE stored_values_tmp;
   END$$
DELIMITER ;

最后,请致电程序:

CALL SPLIT_STR_AND_RETURN('6772:15499:15497',':');

答案 2 :(得分:0)

这是解决方案并且它会起作用,但前提是你确定连接id的最大数量是5 ...如果某处有6个,那么你需要扩展查询:

SELECT tx.id, CONCAT_WS(':', t1.name, t2.name, t3.name, t4.name, t5.name) as var
FROM (SELECT id, SUBSTRING_INDEX(var, ':', 1) as sub,          
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 0,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 1)), ':') FROM (SUBSTRING_INDEX(var, ':', 2))), '') as sub2,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 1,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 2)), ':') FROM (SUBSTRING_INDEX(var, ':', 3))), '') as sub3,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 2,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 3)), ':') FROM (SUBSTRING_INDEX(var, ':', 4))), '') as sub4,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 3,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 4)), ':') FROM (SUBSTRING_INDEX(var, ':', 5))), '') as sub5
       FROM table2) as tx
LEFT JOIN table1 t1
ON tx.sub = t1.id
LEFT JOIN table1 t2
ON tx.sub2 = t2.id
LEFT JOIN table1 t3
ON tx.sub3 = t3.id
LEFT JOIN table1 t4
ON tx.sub4 = t4.id
LEFT JOIN table1 t5
ON tx.sub5 = t5.id

这是{4}}

的SQL小提琴

这个解决方案不是最优雅,但它可以完成这项工作。

也是这个

SELECT id, SUBSTRING_INDEX(var, ':', 1) as sub,          
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 0,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 1)), ':') FROM (SUBSTRING_INDEX(var, ':', 2))), '') as sub2,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 1,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 2)), ':') FROM (SUBSTRING_INDEX(var, ':', 3))), '') as sub3,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 2,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 3)), ':') FROM (SUBSTRING_INDEX(var, ':', 4))), '') as sub4,
           IF((LENGTH(var) - LENGTH(REPLACE (var, ':', ''))) > 3,  
           TRIM(LEADING CONCAT((SUBSTRING_INDEX(var, ':', 4)), ':') FROM (SUBSTRING_INDEX(var, ':', 5))), '') as sub5
       FROM table2

部分代码会像这样返回表格

 +----+---------+---------+---------+---------+---------+
 | id |sub1     |sub2     |sub3     |sub4     |sub5     |  
 +----+---------+---------+---------+---------+---------+
 |123 |6773     |15500    |15479    |         |         |
 +----+---------+---------+---------+---------+---------+
 |543 |15497    |1        |         |         |         |
 +----+---------+---------+---------+---------+---------+
  ...

这里是Faddle http://sqlfiddle.com/#!2/8a2f50/1

所以你可以用它以某种方式在基表上执行其他操作,如更新,搜索或类似的东西......

GL!