2015-02-04 2 views
1

Следующий пример - моя база данных.Mysql group_concat ограничить строки в группе

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

, но это не результат я ищу, то результат будет таким.

Выберите например: выберите Dest, GROUP_CONCAT (ограничение порт 2) от tb_port а, б, tb_dest tb_rule с, где a.id = c.id_port и b.id = c.id_dest группа по Dest

результата Я хотел бы

network 80,22 
network 53,3128 
network 443

Как достичь этого результата только с помощью SQL?

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

+0

Сколько портов вы получите? Более 5? Что бы максимум? – Mihai

+0

Сено, на линию предел 2 порта. –

+0

Im спрашивает общее количество – Mihai

ответ

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.

+0

спасибо Joachim Isaksson: D этот select é очень прост и объективен. –

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(',') 
+0

спасибо за ответ, но я предпочел предыдущий пост, он проще, хотя его более «профессиональный», спасибо еще раз. –

Смежные вопросы