【问题标题】:Grouping a comma separated value on common data对常用数据的逗号分隔值进行分组
【发布时间】:2012-04-14 13:35:09
【问题描述】:

我有一个表 col1 id int,col2 作为 varchar(逗号分隔值)和第 3 列用于为它们分配组。 表格看起来像

  col1          col2     group
..............................
       1        2,3,4       
       2        5,6        
       3        1,2,5
       4        7,8
       5        11,3
       6        22,8

这只是真实数据的样本,现在我必须为它们分配一个组号,以便输出看起来像

  col1          col2       group
..............................
       1        2,3,4       1
       2        5,6         1
       3        1,2,5       1
       4        7,8         2
       5        11,3        1
       6        22,8        2

分配组号的逻辑是 col2 中字符串的每个相似的逗号分隔值必须与 col2 中的每个位置相同的组号 '2' 那里它必须是相同的组号,但复杂的是 2 ,3,4 在一起,因此如果在 col2 中的任何位置找到它们所有三个 int 值,它们将被分配到同一组。 主要部分是 col2 中的 2,3,4 和 1,2,5 都有 2 所以所有 int 1,2,3,4,5 都必须分配相同的组号。 尝试了与 col2 匹配的存储过程,但没有得到想要的结果

大多数小鬼(我不能使用规范化,因为我负担不起从拥有数百万条记录的原始表中创建新表),即使规范化在我的上下文中也没有帮助。


目前为止...... 我已经设置了组列自动增量,然后编写了这个程序:-

BEGIN
  declare cil1_new,col2_new,group_new int;
  declare done tinyint default 0;
  declare group_new varchar(100);
  declare cur1 cursor for select col1,col2,`group` from company ; 
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
  open cur1;
  REPEAT
  fetch cur1 into col1_new,col2_new,group_new;
  update company set group=group_new where
  match(col2) against(concat("'",col2_new,"'"));
  until  done end repeat;
  close cur1;
  select * from company;
END

这个程序正在运行,没有语法错误,但问题是我没有完全达到预期的结果。

【问题讨论】:

  • 您会接受将您的 CSV 列标准化为另一个表的解决方案吗?
  • 在关系数据库中存储 CSV 就像用自行车拖车一样。
  • 不,因为真正的表在 gb 中太大了,所以我无法对其进行规范化。
  • 很抱歉,构建一个满足您要求的解决方案需要更多时间,我想花在上面的时间。我认为how to split CSV values into seperate values 上的这个链接会让你开始。祝你好运!
  • 我很确定您将花费更多的资源来维护 csv 值而不是规范化数据,此外,仅存储 csv 会比规范化结构提供更差的性能。

标签: mysql stored-procedures csv match-against


【解决方案1】:

这是可能的,但我不确定这在你的大桌子上需要多长时间。我假设您可以创建一个包含所有组的新表,并且在填充组列时有数字。

此外,这不能在活动表上运行。不可能写出来,所以这不是我设计的限制。想想如果你添加一个值为 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 ;         

这是 Jay Pipes split_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 ;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    相关资源
    最近更新 更多