2013-03-17 52 views
5

我正在清理存儲在MySQL表中的記錄。如果一行包含%X%,則需要刪除該行及其下方的行,而不管內容如何。例如。 (抱歉,如果表被侮辱任何人的智力):在MySQL中刪除關係中的記錄?

| 1 | leave alone 
| 2 | Contains %X% - Delete 
| 3 | This row should also be deleted 
| 4 | leave alone 
| 5 | Contains %X% - Delete 
| 6 | This row should also be deleted 
| 7 | leave alone 

有沒有辦法做到這一點只用了幾個疑問?或者我將不得不首先執行SELECT查詢(使用%x%搜索參數),然後遍歷這些結果並執行DELETE ... WHERE對於每個返回的索引+ 1

+0

@Aiaias:這是一個完全不同的問題。 – duskwuff 2013-03-17 04:34:49

回答

0

沒有合理的方法來做到這一點在一個查詢中。 (這可能是可能的,但你最終不得不使用查詢將是不合理的複雜,而且幾乎肯定無法移植到其他的SQL引擎。)

使用您所描述的SELECT-THEN-DELETE方法你的問題。

2

這應該工作,雖然它有點笨重的(可能要檢查的LIKE參數,因爲它使用模式匹配(見註釋) DELETE FROM tabledb WHERE idcol IN (SELECT idcol FROM dbtable WHERE col LIKE '%X%') 或idcol IN (SELECT idcol+1 FROM分貝.WHERE col` LIKE '%X%')

+0

這依賴於ID中沒有差距。 – CBroe 2013-03-17 04:53:40

+0

是的,這是非常真實的 – Tucker 2013-03-17 04:57:37

+0

LIKE不使用regexes,REGEXP確實;請參閱http://dev.mysql.com/doc/refman/5.6/en/string-comparison-functions.html#operator_like – ysth 2013-03-17 05:45:33

1

假設表被命名爲test幷包含名爲0列和data

我們從一個SELECT,讓我們有前面的排(所有ID的最高ID低於我們當前行的ID),所有行的id:

SELECT t1.id FROM test t1 
    JOIN test t2 ON 
    (t2.id, true) 
     = 
    (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
     WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 

這使我們的ID 3他們前面的第2和第5行包含%X%,所以這很好。

現在讓我們得到包含%X%並與前面的結合他們行的ID,通過UNION:

(SELECT t1.id FROM test t1 
    JOIN test t2 ON 
    (t2.id, true) 
     = 
    (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
     WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 
) 
UNION 
(
    SELECT id FROM test WHERE data LIKE '%X%' 
) 

這給了我們3,6,2,5 - 真好!

現在,我們無法從表中刪除並從MySQL中的同一張表中選擇 - 因此,我們使用臨時表,將要刪除的ID存儲在那裏,然後從該臨時表中讀取以刪除從我們原來的表:

CREATE TEMPORARY TABLE deleteids (id INT); 

INSERT INTO deleteids 
    (SELECT t1.id FROM test t1 
    JOIN test t2 ON 
     (t2.id, true) 
     = 
     (SELECT t3.id, t3.data LIKE '%X%' FROM test t3 
      WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1) 
) 
    UNION 
    (
    SELECT id FROM test WHERE data LIKE '%X%' 
); 

    DELETE FROM test WHERE id in (SELECT * FROM deleteids); 

...我們留下了我們test表的ID 1,4和7!

(並且由於前面的行使用<,ORDER BY和LIMIT來選擇,所以如果ID不連續,這也可以工作。)

1

你可以做到這一切在一個單一的DELETE聲明:

假設「行之後立即」是根據您的基於INT-ID列的順序,你可以使用MySQL變量分配行號上佔差距在你的ID:

DELETE a FROM tbl a 
JOIN (
    SELECT a.id, b.id AS nextid 
    FROM (
     SELECT  a.id, a.text, @rn:[email protected]+1 AS rownum 
     FROM  tbl a 
     CROSS JOIN (SELECT @rn:=1) rn_init 
     ORDER BY a.id 
    ) a 
    LEFT JOIN (
     SELECT  a.id, @rn2:[email protected]+1 AS rownum 
     FROM  tbl a 
     CROSS JOIN (SELECT @rn2:=0) rn_init 
     ORDER BY a.id 
    ) b ON a.rownum = b.rownum 
    WHERE a.text LIKE '%X%' 
) b ON a.id IN (b.id, b.nextid) 

SQL Fiddle Demo (added additional data for example)


這樣做是它第一次把你的數據和定級它基於您的ID列,然後我們對幾乎相同的結果集執行偏移量LEFT JOIN,但排名列落後於1。這得到了行和他們的直接「下一個」行並排,這樣我們就可以在父DELETE聲明同時拉兩個相應的ID的:

SELECT a.id, a.text, b.id AS nextid, b.text AS nexttext 
FROM (
    SELECT  a.id, a.text, @rn:[email protected]+1 AS rownum 
    FROM  tbl a 
    CROSS JOIN (SELECT @rn:=1) rn_init 
    ORDER BY a.id 
) a 
LEFT JOIN (
    SELECT  a.id, a.text, @rn2:[email protected]+1 AS rownum 
    FROM  tbl a 
    CROSS JOIN (SELECT @rn2:=0) rn_init 
    ORDER BY a.id 
) b ON a.rownum = b.rownum 
WHERE a.text LIKE '%X%' 

產量:

ID  | TEXT     | NEXTID | NEXTTEXT 
2  | Contains %X% - Delete | 3  | This row should also be deleted 
5  | Contains %X% - Delete | 6  | This row should also be deleted 
257 | Contains %X% - Delete | 3434  | This row should also be deleted 
4000 | Contains %X% - Delete | 4005  | Contains %X% - Delete 
4005 | Contains %X% - Delete | 6000  | Contains %X% - Delete 
6000 | Contains %X% - Delete | 6534  | This row should also be deleted 

我們那麼JOIN-DELETE整個陳述條件是它刪除ID是「後選」IDNEXTID的行。