それは可能ですが、これがあなたの非常に大きなテーブルにどれくらいの時間がかかるかはわかりません。グループ列にデータが入力されると、すべてのグループとそこに番号を保持する新しいテーブルを作成できると思います。
また、これはライブテーブルでは実行できません。書くことができないので、私のデザインの制限ではありません。値7と「6,7」の新しい行を追加した場合にどうなるかを考えてください。これにより、グループ1と2がブリッジされ、すべての作業を削除する必要があります。
このプロシージャは、テーブルに追加されるたびに再実行する必要があります。それが受け入れられない場合は、一度実行してから、値を維持し、必要に応じてグループをマージするトリガーに置き換えます。
手順は次のとおりです。モジュール化の恩恵を受ける可能性がありますが、機能します。Jay Pipesのsplit_string関数を使用して、それを含めました。
まず、DDLといくつかのテストデータ
CREATE TABLE `company` (
`col1` int(11) DEFAULT NULL,
`col2` varchar(100) DEFAULT NULL,
`grp` int(11) DEFAULT NULL
);
CREATE TABLE `groups` (
`number` int(11) NOT NULL DEFAULT '0',
`grp` int(11) NOT NULL DEFAULT '0',
`processed` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`number`,`grp`),
KEY `grp` (`grp`)
);
insert into company (col1, col2) values
(1,'2,3,4'),
(2,'5,6'),
(3,'1,2,5'),
(4,'7,8'),
(5,'11,3'),
(6,'22,8');
そして今、手順
use test;
drop procedure if exists group_it;
delimiter //
create procedure group_it ()
begin
declare current_group int default 0;
declare ids varchar(100);
-- clear out all data from before
update company set grp = null;
truncate groups;
main: loop
-- take one unmapped (new group)
set ids := null;
select col2 into ids from company where grp is null limit 1;
if ids is null then
leave main;
end if;
set current_group := current_group + 1;
-- put each value into groups table and mark as unprocessed
call split_string(ids, ',');
insert into groups select value, current_group, false from SplitValues;
-- while unprocessed value in groups
begin
declare unprocessed int;
unprocessed: loop
set unprocessed = null;
select number
into unprocessed
from groups
where not processed
limit 1;
if unprocessed is null then
leave unprocessed;
end if;
begin
-- find all rows in company that matches this group
declare row_id int;
declare ids2 varchar(100);
declare cur2_done boolean;
declare cur2 cursor for
select col1, col2
from company
where col2 regexp concat('^', unprocessed, '$')
or col2 regexp concat('^', unprocessed, ',')
or col2 regexp concat(',', unprocessed, '$')
or col2 regexp concat(',', unprocessed, ',');
declare continue handler for not found set cur2_done := true;
open cur2;
numbers: loop
set cur2_done := false;
fetch cur2 into row_id, ids2;
if cur2_done then
close cur2;
leave numbers;
end if;
update company set grp = current_group where col1 = row_id;
-- add all new values to groups marked as unprocessed
call split_string(ids2, ',');
insert ignore into groups select value, current_group, false from SplitValues;
end loop numbers;
update groups set processed = true where number = unprocessed;
end;
end loop unprocessed;
end;
end loop main;
end//
delimiter ;
これはJayPipessplit_stringです
DELIMITER //
DROP PROCEDURE IF EXISTS split_string //
CREATE PROCEDURE split_string (
IN input TEXT
, IN `delimiter` VARCHAR(10)
)
SQL SECURITY INVOKER
COMMENT
'Splits a supplied string using using the given delimiter,
placing values in a temporary table'
BEGIN
DECLARE cur_position INT DEFAULT 1 ;
DECLARE remainder TEXT;
DECLARE cur_string VARCHAR(1000);
DECLARE delimiter_length TINYINT UNSIGNED;
DROP TEMPORARY TABLE IF EXISTS SplitValues;
CREATE TEMPORARY TABLE SplitValues (
value VARCHAR(1000) NOT NULL PRIMARY KEY
) ENGINE=MyISAM;
SET remainder = input;
SET delimiter_length = CHAR_LENGTH(delimiter);
WHILE CHAR_LENGTH(remainder) > 0 AND cur_position > 0 DO
SET cur_position = INSTR(remainder, `delimiter`);
IF cur_position = 0 THEN
SET cur_string = remainder;
ELSE
SET cur_string = LEFT(remainder, cur_position - 1);
END IF;
IF TRIM(cur_string) != '' THEN
INSERT INTO SplitValues VALUES (cur_string);
END IF;
SET remainder = SUBSTRING(remainder, cur_position + delimiter_length);
END WHILE;
END //
DELIMITER ;