Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Nhóm một giá trị được phân tách bằng dấu phẩy trên dữ liệu chung

Có thể làm được nhưng tôi không chắc việc này sẽ diễn ra trên bàn rất lớn của bạn trong bao lâu. Tôi giả sử rằng bạn được phép tạo một bảng mới chứa tất cả các nhóm và có các số khi cột nhóm được điền.

Ngoài ra, điều này không thể chạy trên bàn trực tiếp. Không thể viết nó nên nó không phải là giới hạn trong thiết kế của tôi. Hãy nghĩ về điều gì sẽ xảy ra nếu bạn thêm một hàng mới với các giá trị 7 và '6,7', hàng này sẽ nối nhóm 1 và 2 và tất cả công việc sẽ phải bị hủy bỏ.

Proc này cần được chạy lại mỗi khi có bổ sung vào bảng. Nếu điều đó không được chấp nhận, hãy chạy nó một lần và sau đó thay thế nó bằng trình kích hoạt duy trì các giá trị và hợp nhất các nhóm khi cần thiết.

Đây là thủ tục. Nó có thể được hưởng lợi từ một số mô-đun hóa nhưng nó hoạt động. Tôi đã lấy Jay Pipes split_string chức năng và bao gồm nó.

Đầu tiên là DDL và một số dữ liệu thử nghiệm

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');

Và bây giờ là thủ tục

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 ;         

Đây là 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 ;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. UTF-8 sự cố PHP / MySQL

  2. Piping mysqldump tới mysql

  3. Nhận tất cả trẻ em theo cha mẹ trong truy vấn mysql

  4. Làm cách nào để lấy số hàng được 'trả về' từ tập kết quả của một thủ tục được lưu trữ

  5. Làm thế nào để xóa đệ quy các mục khỏi bảng?