Mysql group_concat限制分组中的行

时间:2015-02-04 19:14:58

标签: mysql

下一个例子是我的数据库。

tb_port
id  port
1   80
2   22
3   53
4   3128
5   443
tb_dest
id  dest
1   network
2   local
tb_rule
id  id_port id_dest
1   1       1
2   2       1
3   3       1
4   4       1
5   5       1

选择: select dest,group_concat(port) from tb_port a, tb_dest b, tb_rule c where a.id=c.id_port and b.id=c.id_dest group by dest

结果: network 80,22,53,3128,443

但不是我要找的结果,结果就是这个。

选择前: 从tb_port a,tb_dest b,tb_rule c中选择dest,group_concat(端口限制2),其中a.id = c.id_port和b.id = c.id_dest group by dest

结果我想要

network    80,22
network 53,3128
network 443

如何仅使用SQL实现此结果?

Sqlfiddle:http://sqlfiddle.com/#!2/d11807

2 个答案:

答案 0 :(得分:2)

MySQL并不容易使这种查询变得容易,但是一个(当然不是很漂亮)解决方案是使用变量为每个行提供每个dest的序列号,并按行号整数除以2进行分组在每组中得到两个数字;

SELECT dest, GROUP_CONCAT(port ORDER BY rank) ports
FROM (
  SELECT dest, port, ( 
      CASE dest WHEN @curDest 
                THEN @curRow := @curRow + 1 
                ELSE @curRow := 1 AND @curDest := dest END) rank
  FROM tb_port a
  JOIN tb_rule c ON a.id = c.id_port
  JOIN tb_dest b ON b.id = c.id_dest, 
    (SELECT @curRow := 0, @curDest := '') r
  ORDER BY dest
) z
GROUP BY FLOOR(rank/2),dest
ORDER BY dest, MIN(rank)

An SQLfiddle to test with

答案 1 :(得分:1)

这是一个存储过程,你只需在调用时放入分隔符

DELIMITER $$

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

  BEGIN

    DECLARE id TEXT;
    DECLARE value TEXT;
    DECLARE occurance INT DEFAULT 0;
    DECLARE i INT DEFAULT 0;
    DECLARE splitted_value TEXT;
    DECLARE done INT DEFAULT 0;
    DECLARE cur1 CURSOR FOR  
     select dest,group_concat(port) from tb_port a, tb_dest b, tb_rule c 
     where a.id=c.id_port and b.id=c.id_dest and  dest != '' group by dest;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    DROP TEMPORARY TABLE IF EXISTS table2;
    CREATE TEMPORARY TABLE table2(
    `id` VARCHAR(255),
    `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(CONCAT(value,bound))
                                 - LENGTH(REPLACE(CONCAT(value,bound), bound, ''))
                                 +1);
        SET i=2;
        WHILE i <= occurance DO
          SET splitted_value =
          SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(value,bound),bound,i),bound,-2) ;

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

        END WHILE;
      END LOOP;

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



 CALL explode_table(',')