2016-08-15 50 views
0

以逗号分隔的字段值编写存储过程我有一个数据库表像这样的例子:其标志复制在MySQL

ID THINGS   HAS_DUPLICATES 
1 AAA, BBB, AAA  NULL 
2 CCC, DDD   NULL 

我想写一个存储过程的东西场标志重复的值。 调用该过程后,表将变成这个样子:

ID THINGS   HAS_DUPLICATES 
1 AAA, BBB, AAA  YES 
2 CCC, DDD   NO 

请注意,我想只使用SQL和不归我的数据库来解决它。我也知道像编写PHP代码的其他方法。

+2

'“不归我的数据库“ - 为什么?使用正确的工具进行工作通常是首选方法。 – David

+0

你知道可以存储在'things'中的最大值吗?如果你这样做,你可以使用'substring_index'来创建多个列,然后进行比较,而不需要'动态sql'或'存储过程'。 – sgeddes

+0

我相信user148有一线希望,在不久的将来 – Drew

回答

0

这是对我的问题的答案,假设THINGS字段中的数据由一个“|”分隔。我们原来的表会MYTABLE:

ID THINGS   THINGSCount THINGSCountUnique HAS_DUPLICATES 
1 AAA|BBB|AAA  NULL   NULL    NULL 
2 CCC|DDD   NULL   NULL    NULL 

步骤1.检查中,通过棒分隔值的最大数量“|”在物联网领域:

SELECT ROUND((CHAR_LENGTH(THINGS) - CHAR_LENGTH(REPLACE(THINGS,'|','')))/CHAR_LENGTH('|')) + 1 FROM myTABLE; 

步骤2.假设步骤1的答案7,现在用下面的SQL来的东西现场为行的数据拆分,还有很多其他的方法,你可以向谷歌不要分裂:

CREATE TABLE myTABLE_temp 
SELECT ID, SUBSTRING_INDEX(SUBSTRING_INDEX(myTABLE.THINGS, '|', n.n), '|', -1) THINGS 
FROM myTABLE JOIN 
(SELECT n FROM 
(SELECT 1 AS N UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7) a) n 
ON CHAR_LENGTH(THINGS) - CHAR_LENGTH(REPLACE(THINGS, '|', '')) >= n - 1 
ORDER BY ID; 

我们myTABLE_temp表将是这样的:

ID THINGS 
1 AAA 
1 BBB 
1 AAA 
2 CCC 
2 DDD 

步骤3。在这里,我们创建了两个新的表来保存COUNT(的东西)和COUNT(DISTINCT的东西)如下:

# THINGSCount 
CREATE TABLE myTABLE_temp_2 
SELECT ID, COUNT(THINGS) AS THINGSCount FROM myTABLE_temp GROUP BY ID; 
# Remember to ADD INDEX to ID field 
UPDATE myTABLE A INNER JOIN myTABLE_temp_2 B ON(A.ID = B.ID) SET A.THINGSCount = B.THINGSCount; 

# THINGSCountUnique 
CREATE TABLE myTABLE_temp_3 
SELECT ID, COUNT(THINGS) AS THINGSCountUnique FROM myTABLE_temp GROUP BY ID; 
# Remember to ADD INDEX to ID field 
UPDATE myTABLE A INNER JOIN myTABLE_temp_3 B ON(A.ID = B.ID) SET A.THINGSCountUnique = B.THINGSCountUnique; 

最后一步:标志重复值:

UPDATE myTABLE SET HAS_DUPLICATES = IF(THINGSCount>THINGSCountUnique, 'DUPLICATES', 'NO'); 
1

模式:

DROP TABLE IF EXISTS evilThings; -- orig table with dupes 
CREATE TABLE evilThings 
( ID INT AUTO_INCREMENT PRIMARY KEY, 
    THINGS TEXT NOT NULL, 
    HAS_DUPLICATES INT NULL 
); 
INSERT evilThings(ID,THINGS) VALUES 
(1,"'AAA, BBB, AAA'"), 
(2,"'CCC, DDD'"); 


CREATE TABLE notEvilAssocTable 
( ai INT AUTO_INCREMENT PRIMARY KEY, -- no shuffle on inserts 
    ID INT NOT NULL, 
    THING VARCHAR(100) NOT NULL, 
    UNIQUE KEY `unqK_id_thing` (ID,THING) -- no dupes, this is honorable 
); 

存储过程:

DROP PROCEDURE IF EXISTS splitEm; 
DELIMITER $$ 
CREATE PROCEDURE splitEm() 
BEGIN 
    DECLARE lv_ID,pos1,pos2,comma_pos INT; 
    DECLARE lv_THINGS TEXT; 
    DECLARE particle VARCHAR(100); 
    DECLARE strs_done INT DEFAULT FALSE; -- string search done 
    DECLARE done INT DEFAULT FALSE; -- cursor done 
    DECLARE cur111 CURSOR FOR SELECT ID,THINGS FROM evilThings ORDER BY ID; 
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 
    -- Please note in the above, CURSOR stuff MUST come LAST else "Error 1337: Variable or condition decl aft curs" 
    -- ------------------------------------------------------------------------------------------------------------------- 
    TRUNCATE TABLE notEvilAssocTable; 

    OPEN cur111; 

    read_loop: LOOP 
     SET strs_done=FALSE; 
     FETCH cur111 INTO lv_ID,lv_THINGS; 

     IF done THEN 
      LEAVE read_loop; 
     END IF; 
     SET pos1=1,comma_pos=0; 
     WHILE !strs_done DO 
      SET pos2=LOCATE(',', lv_THINGS, comma_pos+1); 
      IF pos2=0 THEN 
       SET pos2=LOCATE("'", lv_THINGS, comma_pos+1); 
       IF pos2!=0 THEN 
        SET particle=SUBSTRING(lv_THINGS,comma_pos+1,pos2-comma_pos-1); 
        SET particle=REPLACE(particle,"'",""); 
        SET particle=TRIM(particle); 
        INSERT IGNORE notEvilAssocTable (ID,THING) VALUES (lv_ID,particle); 
       END IF; 
       SET strs_done=1; 
      ELSE 
       SET particle=SUBSTRING(lv_THINGS,comma_pos+1,pos2-comma_pos-1); 
       SET particle=REPLACE(particle,"'",""); 
       SET particle=TRIM(particle); 
       INSERT IGNORE notEvilAssocTable (ID,THING) VALUES (lv_ID,particle); 
       SET comma_pos=pos2; 
      END IF; 
     END WHILE; 
    END LOOP; 
    CLOSE cur111; -- close the cursor 
END$$ 
DELIMITER ; 

测试:

call splitEm(); 

见分裂的结果:

select * from notEvilAssocTable; 

enter image description here

请注意位置3,InnoDB差距(来自INSERT IGNORE)。这只是innodb差异异常,像InnoDB那么多的预期副作用。在这种情况下,由IGNORE驱动的部分造成了缺口。没问题,但。它禁止在我们的新表中拆分重复。是很常见。它在那里保护你。

如果你不想在db的字符串的开始和结尾有单引号,那么相应地改变例程。

+0

谢谢@Drew提供了这个很好的答案。我试过了,它正在工作,但我不能将它标记为我的问题的答案,因为我想FLAG重复不删除它们。请检查我对这个问题的回答。 – user1483799

+0

这很好,我很高兴你解决了你的问题。 – Drew