在同一个表和限制子句上使用join进行删除

时间:2013-09-06 07:13:28

标签: mysql sql

我有一个像这样的MySql表,

Session_Id Subscriber_Id Status
-------------------------------
abc     1234    Started
bcd     1235    Started
bcd     1235    Finished

我需要删除状态为“已启动”的行,只有后跟“已完成”。这是一张很大的表,所以我一次会删除1000条记录。

我读了一些类似的帖子, Multiple-table DELETE LIMITDELETE FROM `table` AS `alias` ... WHERE `alias`.`column` ... why syntax error?

并尝试了以下查询,

mysql> delete a.* from FSESSION as a, FSESSION as b where a.status='Started' and b.status='Finished' and a.session_id=b.session_id limit 1000;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 1000' at line 1  ----> If I remove 'limit' this works

mysql> DELETE FROM v USING `FSESSION` AS v WHERE status = 'Started' and exists(select 0 from FSESSION t where t.status='Finished' and v.session_id=t.session_id) limit 1000;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 1000' at line 1 ---->

即使删除限制也不起作用。

我使用MySql版本5.1.56-ndb-7.1.15。请建议一种方法来做到这一点。谢谢!

2 个答案:

答案 0 :(得分:1)

尝试以下查询:

CREATE TEMPORARY TABLE FSESSION_TEMP
(
    Temp_Session_Id varchar(255)
);

INSERT INTO FSESSION_TEMP 
(
SELECT a.Session_Id FROM
    FSESSION a, 
    FSESSION b
WHERE 
    a.Status = 'Started' and 
    b.Status = 'Finished' and
    a.Session_ID = b.Session_ID
  LIMIT 2
);


DELETE FROM 
    FSESSION 
WHERE 
    Session_ID in (SELECT * FROM FSESSION_TEMP)
;

DROP TABLE FSESSION_TEMP;

这是SQL Fiddle。我将LIMIT设置为2以表明它有效。您仍然需要将其更改为1000。

由于以下两个原因,您似乎需要使用临时表:

1)当您在子查询中使用相同的表时,MySQL不允许您从表中删除

2)对于多表语法,DELETE从每个tbl_name中删除满足条件的行。在这种情况下,不能使用ORDER BY和LIMIT(直接取自MYSQL DELETE manual


通过DELETE使用JOIN语法并使用派生表(与上述临时表相同)连接原始表(将从中删除行),有一种方法可以绕过限制):

DELETE fdel
FROM 
    FSESSION fdel
  JOIN
    (
    SELECT a.Session_Id 
    FROM
        FSESSION a
      JOIN 
        FSESSION b
      ON a.Session_ID = b.Session_ID
    WHERE 
        a.Status = 'Started' and 
        b.Status = 'Finished' 
      LIMIT 2
    ) ftemp
  ON ftemp.Session_ID = fdel.Session_ID
;

答案 1 :(得分:1)

根据您的评论

更新

DELETE f
  FROM fsession f JOIN
(
  SELECT session_id, subscriber_id
    FROM fsession
   WHERE status IN('Started', 'Finished')
   GROUP BY Session_Id, Subscriber_Id
  HAVING MAX(status = 'Started')  > 0
     AND MAX(status = 'Finished') > 0
  LIMIT 1000 -- limit here means how many pairs of rows, so it's effectively 2x rows
) q ON f.session_id = q.session_id
   AND f.subscriber_id = q.subscriber_id

要知道删除了多少行,请使用ROW_COUNT()

SELECT ROW_COUNT();

这是 SQLFiddle 演示