函数解析:
SUBSTRING(s, start, length) :从字符串 s 的 start 位置截取长度为 length 的子字符串
- 举例:从字符串 RUNOOB 中的第 2 个位置截取 3个 字符
- SELECT SUBSTRING("RUNOOB", 2, 3) AS ExtractString; -- UNO
SUBSTRING_INDEX(s, delimiter, number) :返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。
如果 number 是正数,返回第 number 个字符左边的字符串。
如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串。
- 举例
- SELECT SUBSTRING_INDEX('ab','',1) -- a
- SELECT SUBSTRING_INDEX('ab','',-1) -- b
- SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('abcde','',3),'',-1) -- c
需求:
需要将数据库中的字符串,如:'1,1,0,12,0,2,1,0,1,0,0,0,1,0,0,0,0,0,2,0,0,0,0,1,1,1,0,1,0,2 ' 30位中的前7位取出来,并按 ' , ' 分隔,分隔后求和;
- SQL1(有误):
- 思路1(有误):将位置为第 1、3、5、7、9、11、13的分别取出来,然后再求和
- 问题所在点:若前 7 位数字都是 1 位的数字,则此 sql 可以适用,若当中有 2 位 或 2位以上 的数字,则此sql 就会出现问题,如上字符串的前 7 位 '1,1,0,12,0,2,1',则通过此 sql 查询出来的结果为 1 1 0 1 , 0 2 这 7 位,其中会包含 ' , '分隔符,故此 sql 不能通用
SELECT
t1.warehouse_id,
t1.compute_pses AS '30天销量',
SUBSTRING( t1.compute_pses, 1, 1 ) AS sale1,
SUBSTRING( t1.compute_pses, 3, 1 ) AS sale2,
SUBSTRING( t1.compute_pses, 5, 1 ) AS sale3,
SUBSTRING( t1.compute_pses, 7, 1 ) AS sale4,
SUBSTRING( t1.compute_pses, 9, 1 ) AS sale5,
SUBSTRING( t1.compute_pses, 11, 1 ) AS sale6,
SUBSTRING( t1.compute_pses, 13, 1 ) AS sale7,
(
SUBSTRING( t1.compute_pses, 1, 1 ) + SUBSTRING( t1.compute_pses, 3, 1 ) + SUBSTRING( t1.compute_pses, 5, 1 ) + SUBSTRING( t1.compute_pses, 7, 1 ) + SUBSTRING( t1.compute_pses, 9, 1 ) + SUBSTRING( t1.compute_pses, 11, 1 ) + SUBSTRING( t1.compute_pses, 13, 1 )) AS '前七天销量总和'
FROM
e_storage t1
JOIN e_warehouse t2 ON t2.id = t1.warehouse_id
AND t2.tenant_code = '1374904716458332160'
WHERE
t1.state = 'Normal'
AND t2.state = 'Active'
AND t1.tenant_code = '1374904716458332160';
- SQL2:
- 思路二:以逗号为分隔符,如果 number 是正数,返回第 number 个字符左边的字符串,如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串,取得是两个分隔符之间的字符,故可以取出整个完整的数字,不管是几位数,此 sql 可以通用;
SELECT
t1.warehouse_id,
t1.compute_pses AS '30天销量',
SUBSTRING_INDEX( t1.compute_pses, ',', 1 ) AS sale1,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 2 ), ',',- 1 ) AS sale2,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 3 ), ',',- 1 ) AS sale3,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 4 ), ',',- 1 ) AS sale4,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 5 ), ',',- 1 ) AS sale5,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 6 ), ',',- 1 ) AS sale6,
SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 7 ), ',',- 1 ) AS sale7,
(
SUBSTRING_INDEX( t1.compute_pses, ',', 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 2 ), ',',- 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 3 ), ',',- 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 4 ), ',',- 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 5 ), ',',- 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 6 ), ',',- 1 ) + SUBSTRING_INDEX( SUBSTRING_INDEX( t1.compute_pses, ',', 7 ), ',',- 1 )) AS '前七天销量总和'
FROM
e_storage t1
JOIN e_warehouse t2 ON t2.id = t1.warehouse_id
AND t2.tenant_code = '1374904716458332160'
WHERE
t1.state = 'Normal'
AND t2.state = 'Active'
AND t1.tenant_code = '1374904716458332160';
- 思路三:刚开始,其实一开始想到的是写一个function,写完之后,发现效率很低(6.814s),故才想到使用 思路二,函数如下:
CREATE DEFINER=`root`@`%` FUNCTION `split_sum`(str VARCHAR(200)) RETURNS int(20)
DETERMINISTIC
BEGIN
DECLARE max_size INT(11);
DECLARE i INT(11);
DECLARE sum INT(20);
SET max_size = LENGTH(str) - LENGTH(REPLACE(str, ',', '')) + 1;
SET i = 0;
SET sum = 0;
WHILE i < max_size DO
SET i = i + 1;
SET sum = sum + SUBSTRING_INDEX(SUBSTRING_INDEX(str, ',', i),',',-1);
END WHILE;
RETURN sum;
END
- SQL3如下:
SELECT
t1.compute_pses '30天销量',
split_sum (SUBSTRING_INDEX( t1.compute_pses, ',', 7 )) AS '前七天销量总和'
FROM
e_storage t1
JOIN e_warehouse t2 ON t2.id = t1.warehouse_id
AND t2.tenant_code = '1374904716458332160'
WHERE
t1.state = 'Normal'
AND t2.state = 'Active'
AND t1.tenant_code = '1374904716458332160';
若大家有更好的解决办法,欢迎各位大佬多多指导,多多评论,谢谢!