下一个例子是我的数据库。
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
答案 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)
答案 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(',')