2016-08-15 57 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