笛卡尔集

 

想要一个根据两个数字展开的笛卡尔集,下面sql是最初想到的最笨的办法,把每一个数字和第二个数字的数列求并集

比如2,6两个数字的笛卡尔集

遍历2遍,分别是

1,1 

1,2

1,3

1,4

1,6

1,6

2,1

2,2

2,3

2,4

2,5

2,6

然后 union两个集合

CREATE PROCEDURE lcx_demo17 (
    IN channeltype LONG,
    IN deviceid LONG,
    IN address INT,
    IN channel INT
)
BEGIN

    DECLARE i INT ;
    
    SET i = 1;

    SET @strsql = ' SELECT num as address, num as channel FROM t_number WHERE num <= 0 ';

    WHILE i <= address DO

        SET @strsql = CONCAT(@strsql, ' UNION All (SELECT ', i, ' as address, c.num as channel ');
        SET @strsql = CONCAT(@strsql, ' FROM ');
            SET @strsql = CONCAT(@strsql, ' ( ');
                SET @strsql = CONCAT(@strsql, ' SELECT n.num, a.channel FROM t_number n ');
                SET @strsql = CONCAT(@strsql, ' LEFT JOIN (');
                    SET @strsql = CONCAT(@strsql, ' SELECT channel FROM tip_s_analoginputinfo ');
                    SET @strsql = CONCAT(@strsql, ' WHERE channeltype = ', channeltype, ' AND address485 = ', i, ' AND Device_id = ', deviceid);
                SET @strsql = CONCAT(@strsql, ' ) a ON n.num = a.channel ');
                SET @strsql = CONCAT(@strsql, ' WHERE n.num <= ', channel);
            SET @strsql = CONCAT(@strsql, ' ) c');
        SET @strsql = CONCAT(@strsql, ' WHERE c.channel IS NULL) ');
--         SET @strsql = CONCAT(@strsql, ' ORDER BY c.num * 1) ');
    
        SET i = i + 1;

    END WHILE;

SET @strsql = CONCAT(@strsql, ' ORDER BY address, channel ');

--     select @strsql;

    PREPARE stmt FROM @strsql;
    EXECUTE stmt ;
    DEALLOCATE PREPARE stmt;

    
END;

 

其实有一个很简单的方法,就是利用表连接查询时,on 字段始终为 true 时,第一个集合的每一行都会与第二个集合的全部行关联,产生笛卡尔集,见下面的sql

下面的两种方式,一种带子查询,经过测试发现带子查询的 sql 效率相对低一些

SELECT a.num, b.num FROM t_number a 
LEFT JOIN t_number b ON 1=1
WHERE a.num <= 900 AND b.num <= 900
ORDER BY a.num, b.num

 

 

SELECT a.num, b.ch FROM t_number a 
LEFT JOIN
(SELECT num as ch FROM t_number WHERE num <= 16) b ON 1=1
WHERE a.num <= 4
ORDER BY a.num, b.ch

 

 

对比下面两个sql,发现not in 的效率 高于合并两个表后查差集,但这里有个前提,这个前提就是这次的测试中,not in 查出来的集合较小,如果not in 里select返回的集合较大,可能会有不同的效率对比结果

-- 0.002 (4,64)
-- 0.391 (400, 600)
SELECT c.address485, c.channel, COUNT(*) FROM 
(
SELECT a.num as address485, b.num as channel FROM t_number a 
LEFT JOIN t_number b ON 1=1
WHERE a.num <= 4 AND b.num <= 64 

UNION ALL

SELECT address485, channel FROM tip_s_analoginputinfo WHERE channeltype = 10224 AND Device_id = 5 
) c
GROUP BY c.address485,c.channel
HAVING COUNT(*) = 1
ORDER BY c.address485, c.channel

 

-- 0.002 (4,64)
-- 0.278 (400, 600)
SELECT a.num, b.num FROM t_number a 
LEFT JOIN t_number b ON 1=1
WHERE a.num <= 4 AND b.num <= 64 AND CONCAT(a.num,"-",b.num) NOT IN (
 SELECT CONCAT(address485,"-",channel) FROM tip_s_analoginputinfo WHERE channeltype = 10224 AND Device_id = 5)
ORDER BY a.num, b.num

 

posted @ 2021-05-06 18:37  1156740846  阅读(601)  评论(0编辑  收藏  举报