2012-03-30 4 views
3

У меня есть таблица с идентификатором col1 id, 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 вместе, поэтому они все три значения int, если они найдены в любом месте в col2, будут назначены той же группе. Основная часть 2,3,4 и 1,2,5, как в col2, имеют 2, поэтому все int 1,2,3,4,5 должны назначать одну и ту же группу no. Пробная процедура магазина с совпадением против col2, но не получившая желаемого результата

Большинство имп (я не могу использовать нормализацию, потому что я не могу позволить себе создать новую таблицу из моей оригинальной таблицы, которая имеет миллионы записей), даже нормализация не полезно в моем контексте.


Достигнутые до сих пор ...... Ihave установить группу столбцов автоматического приращения, а затем написал эту процедуру: -

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 

Эта процедура работает, не Синтекс ошибка, но не proble что я не ощущаю желаемого результата.

+4

Вы бы принять решение, включавшее нормализации ваш CSV столбец в другую таблицу? – cha0site

+7

Хранение CSV в реляционной базе данных - это как буксировка вашего автомобиля с помощью вашего велосипеда. – Corbin

+1

нет, потому что реальная таблица слишком велика в gb, поэтому я не могу ее нормализовать. –

ответ

0

Возможно, но я не уверен, как долго это займет ваш большой стол. Я предполагаю, что вам разрешено создавать новые таблицы, содержащие все группы, и числа, которые заполняются в столбце группы.

Кроме того, это не может работать на живой таблице. Невозможно написать его, поэтому это не ограничение моего дизайна. Подумайте о том, что произойдет, если вы добавите новую строку со значениями 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 Трубы 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 ; 
Смежные вопросы