在子查询中使用自引用更新行

时间:2012-03-28 08:20:22

标签: mysql sql sql-update subquery

我有一个大约7000行的表,其中大约有4000个错误导致错误。 (该位置为'null' NULL,应该是其他内容。)现在我正在尝试修复几乎所有可能行的数据。

UPDATE `timelog` t
SET `location`=(SELECT location
                FROM timelog tl
                WHERE tl.end_ts=t.end_ts AND location != 'null'
                ORDER BY tl.log_id DESC
                LIMIT 0,1) -- Just to make sure that I get 1 or 0 results
WHERE end_ts > '2012-01-01 00:00:00' AND location = 'null';

但我收到错误:

  

#1093 - 您无法在FROM子句

中为更新指定目标表't'

好吧,似乎我在更新时无法访问行本身如何解决这个问题?

也许使用临时表,但这似乎有点开销,我也必须设法复制所有不相关的行。

我也试过像this answer中解释的那样使用instat一个连接,但是我需要限制所选择的行。


根据答案,我尝试使用临时视图自己的解决方案:

CREATE OR REPLACE VIEW right_locations AS
SELECT l.*, t.end_ts, t.location, (SELECT location FROM timelog tl WHERE tl.end_ts=t.end_ts AND location != 'null' ORDER BY tl.log_id DESC LIMIT 0,1) AS "possible", t.end_location
FROM `log` l
JOIN timelog t ON t.log_id=l.log_id
WHERE l.action_id =7 AND l.ts > '2012-01-01 00:00:00'
ORDER BY end_location;

UPDATE timelog t
JOIN right_locations r ON r.log_id=t.log_id
SET t.location = r.possible
WHERE t.end_ts > '2012-01-01 00:00:00' AND t.location = 'null';

3 个答案:

答案 0 :(得分:2)

我发现的解决方案听起来很有趣。也许你会尝试一下?

http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/

UPDATE timelog t
SET location = (
  select location from (
    SELECT tl.location
    FROM timelog tl
    WHERE tl.end_ts = t.end_ts AND tl.location != 'null'
    ORDER BY tl.log_id DESC
    LIMIT 1
 ) as x
WHERE 
  t.end_ts > '2012-01-01 00:00:00' AND 
  t.location = 'null';

类似的东西?

答案 1 :(得分:1)

您应该能够使用以下内容 -

UPDATE timelog t1
INNER JOIN timelog t2
    ON t1.end_ts = t2.end_ts
    AND t2.location != 'null'
LEFT JOIN timelog t3
    ON t2.end_ts = t3.end_ts
    AND t3.location != 'null'
    AND t2.log_id < t3.log_id
SET t1.location = t2.location
WHERE t1.end_ts > '2012-01-01 00:00:00'
AND t1.location = 'null'
AND t3.log_id IS NULL;

编辑添加LEFT JOIN以强制更新t2中与连接条件匹配的最新值(与ID DESC LIMIT 1的顺序相同)。

答案 2 :(得分:0)

我对mysql的工作量不大,但您可以尝试使用子查询创建视图,然后使用该视图。

create view timelogView
(
SELECT location
FROM timelog tl
WHERE tl.end_ts=t.end_ts AND location != 'null'
ORDER BY tl.log_id DESC
LIMIT 0,1
)

UPDATE `timelog` t
SET `location`=(SELECT location
                FROM timelogView tl) -- Just to make sure that I get 1 or 0 results
WHERE end_ts > '2012-01-01 00:00:00' AND location = 'null';

让我知道是否有效:)