2012-03-28 2 views
0

약 4000 개의 오류가있는 버그가있는 약 7000 개의 행이있는 테이블이 있습니다. 위치는 '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 - You can't specify target table 't' for update in FROM clause

글쎄 내가 그 문제를 풀기가 할 수있는 방법 나는 업데이트하는 동안 행 자체에 액세스 할 수 있다는 것입니까?

어쩌면 임시 테이블과 함께,하지만 그게 너무 관련이없는 모든 행을 복사 관리 할 수있는 약간의 오버 헤드가 될 것 같습니다.

나는 또한 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'; 
+0

왜 곧장 앞으로 가기 조인 대신보기를 사용하고 있습니까? – nnichols

+0

가입 시도가 작동하지 않았습니다. 내 Triest 작업 솔루션은 위에 있습니다. – rekire

+0

최대 값을 얻기 위해 왼쪽 조인을 사용하여 내 솔루션을 사용해 보셨습니까? 뷰와 함께 사용하는 버전과 정확히 동일한 결과를 생성해야합니까? – nnichols

답변

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'; 

경우 작동 :)

+0

답변 해 주셔서 감사합니다. 그러나 이것이 테스트되지 않는다면, 테이블 t는 뷰 정의에서 알 수 없습니다. 하지만 그 조건에 "참여"할 수 있습니다 ... brb – rekire

+0

예, 조건에 tl.end_ts = t.end_ts가 없어야하며 원하지 않으므로 주문하지 않아도됩니다. 선택 결과를 표시합니다. –

+0

이 시도 : 보기 timelogView UPDATE'timelog' t SET'(TimeLog라는의 TL FROM SELECT 위치 )를 만들 location' = TL WHERE t (여기서 위치 = '널'timelogView로부터 위치 를 선택!) .end_ts> '2012-01-01 00:00:00'AND tl.end_ts = t.end_ts AND t.location = 'null'; –

2

솔루션 나는 소리 interessting 발견했다. 어쩌면 당신은 그것을 시도 줄거야?

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'; 

처럼 뭔가?

+0

질문을하기 전에이 페이지를 열어 놓았습니다. 나는 이것을 나의 경우에 사용하는 방법을 모르겠다. – rekire

+0

보이지만 작동하지 않습니다. * # 1064 - SQL 구문에 오류가 있습니다. 귀하의 MySQL 서버 버전에 해당하는 설명서를 확인하여 올바른 구문을 찾으십시오. ''at line 10 * – rekire

+0

답변을 upvoted 나는 도와 줘서 고맙습니다. – rekire

1

다음과 같은 사용할 수 있어야 알려 - (T2)에서 최신 값으로 업데이 트를 강제로 가입

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을 그 조인 기준과 일치합니다 (ID DESC LIMIT 1의 순서와 동일한 효과).

+0

log_id 내 기본 키이며'NULL' 될 수 없습니다. 주요 부분은 작동 할 수 있습니다. – rekire

+0

이 경우 LEFT JOIN ... IS NULL의 개념은 더 높은 id와 일치하지 않는 레코드를 찾는 것이므로,'t3.log_id IS NULL' – nnichols