如何有效地计算MySQL中的序列中断/漏洞?

时间:2013-10-03 11:29:41

标签: mysql sql sequences stored-functions

假设我有以下结果集:

SELECT
    *
FROM
    (
        SELECT 1 as `no`, NULL as `sequence`
        UNION ALL
        SELECT 2, ''
        UNION ALL
        SELECT 3, '1'
        UNION ALL
        SELECT 4, '1,2,3,4,5'
        UNION ALL
        SELECT 5, '2,4,5'
        UNION ALL
        SELECT 6, '1, 5'
        UNION ALL
        SELECT 7, '1,3,5'
    ) as `sub`;

我的任务是计算下面列出的每个sequence的序列中断/漏洞。我写了以下存储函数:

DELIMITER $$

DROP FUNCTION IF EXISTS `countSequenceBreaks`$$

CREATE FUNCTION `countSequenceBreaks`(`sequence` VARCHAR(1000))
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE `delimiter` CHAR DEFAULT ',';

DECLARE `current`, `last` INT;
DECLARE `result` INT DEFAULT 0;

IF
    `sequence` IS NULL
    OR
    NOT LENGTH(`sequence`)
    OR
    NOT INSTR(`sequence`, `delimiter`)
THEN RETURN `result`;
END IF;

SET `current`   = SUBSTRING_INDEX(`sequence`, `delimiter`, 1);
SET `last`      = SUBSTRING_INDEX(`sequence`, `delimiter`, -1);

IF `last` < `current`
THEN
    SET `result`    = `last`;
    SET `last`      = `current`;
    SET `current`   = `result`;
    SET `result`    = 0;
END IF;

WHILE `current` < `last` DO
    IF NOT FIND_IN_SET(`current`, `sequence`)
    THEN SET `result` = `result` + 1;
    END IF;

    SET `current` = `current` + 1;
END WHILE;

RETURN `result`;
END$$

DELIMITER ;

但是我担心WHILE - 循环可能需要对不同的序列成员进行太多迭代并导致查询减速。

问题:

  1. 有没有办法改善存储功能
  2. 如果有办法,那怎么办?

  3. 我的调试查询:

    SELECT
        `no`, `sequence`, `countSequenceBreaks`(`sequence`)
    FROM
        (
            SELECT 1 as `no`, NULL as `sequence`
            UNION ALL
            SELECT 2, ''
            UNION ALL
            SELECT 3, '1'
            UNION ALL
            SELECT 4, '1,2,3,4,5'
            UNION ALL
            SELECT 5, '2,4,5'
            UNION ALL
            SELECT 6, '1, 5'
            UNION ALL
            SELECT 7, '1,3,5'
        ) as `sub`;
    

    结果集:

    no sequence   `countSequenceBreaks`(`sequence`)
    -----------------------------------------------
    1  NULL       0
    2             0
    3  1          0
    4  1,2,3,4,5  0
    5  2,4,5      1
    6  1,5        3
    7  1,3,5      2
    

    问候。

1 个答案:

答案 0 :(得分:1)

您可以通过一个简单的查询来完成:

select sequence,  
CASE WHEN NOT INSTR(IFNULL(sequence,''), ',') THEN 0
     ELSE 
       (
         SUBSTRING_INDEX(sequence,',' ,-1)
         -SUBSTRING_INDEX(sequence,',' , 1)
        ) 
        -
        (LENGTH(sequence)-LENGTH(REPLACE(sequence,',','')))
END countSequenceBreaks

from t

如何查找序列中断的计数?

例如1,3,5序列。

所有我们需要知道的休息计数是计算错过的分隔符的数量。在这种情况下,完整字符串1,2,3,4,5包含5-1=4分隔符,但1,3,5序列仅包含2个分隔符,因此中断计数(错过的数字 - 等于您可以看到的错过分隔符的数量)= 4-2 = 2

如何知道字符串中分隔符的数量?

在我们的情况下,当分隔符有一个符号长度时,它是(LENGTH(sequence)-LENGTH(REPLACE(sequence,',',''))

SQLFiddle demo