2

次の結果セットがあるとします。

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-loop が異なるシーケンスメンバーに対してあまりにも多くの反復を行い、クエリの速度が低下する可能性があることを心配しています.

質問:

  1. 保存された関数を改善する方法はありますか?
  2. 方法があるとすれば、どのように?

私のデバッグクエリ:

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

よろしく。

4

1 に答える 1

1

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含まれていますが、シーケンスには区切り文字が 2 つしか含まれていないため、区切りの数 (欠落した数字 - 見ればわかるように、欠落した区切り文字の数に等しい)5-1=41,3,5= 4-2 = 2

文字列内の区切り文字の数を知る方法は?

私たちの場合、デリミタに 1 つのシンボル長がある場合、それは(LENGTH(sequence)-LENGTH(REPLACE(sequence,',',''))

SQLFiddle デモ

于 2013-10-03T12:59:42.750 に答える