LEFT JOIN을 사용하여 MySQL에서 여러 테이블 업데이트


165

두 개의 테이블이 있고 LEFT JOIN의 모든 행에 대해 T1의 필드를 업데이트하려고합니다.

쉬운 예를 들어, 다음 결과 집합의 모든 행을 업데이트하십시오.

SELECT T1.* FROM T1 LEFT JOIN T2 ON T1.id = T2.id WHERE T2.id IS NULL  

MySQL을 수동 상태가 :

다중 테이블 UPDATE 문은 LEFT JOIN과 같은 SELECT 문에 허용 된 모든 유형의 조인을 사용할 수 있습니다.

그러나 문서화 된 다중 테이블 UPDATE에서 올바른 구문을 찾을 수 없습니다.

올바른 구문은 무엇입니까?

답변:


318
UPDATE  t1
LEFT JOIN
        t2
ON      t2.id = t1.id
SET     t1.col1 = newvalue
WHERE   t2.id IS NULL

A에 대한주의 SELECT가 사용하는 것이 더 효율적인 것 NOT IN/ NOT EXISTS구문 :

SELECT  t1.*
FROM    t1
WHERE   t1.id NOT IN
        (
        SELECT  id
        FROM    t2
        )

성능 세부 정보는 내 블로그의 기사를 참조하십시오.

불행히도 명령문 MySQL의 하위 쿼리에서 대상 테이블 UPDATE을 사용할 수 없으므로 LEFT JOIN구문 이 덜 효율적 이어야합니다.


Oracle에서는 작동하지 않습니다. 이 경우이 게시물 을 참조하십시오 .
Jon Ander

이것에 제한을 추가 할 수 있습니까? 한 번에 10000 개의 행을 업데이트하고 싶습니다. LIMIT 10000을 추가하면 '업데이트 및 제한의 잘못된 사용법'이라는 오류가 표시됩니다
Haril Satra

28

데이터가 정규화 된 시나리오에도 동일하게 적용 할 수 있지만 이제 테이블에 세 번째 테이블에서 값을 찾도록하려고합니다. 다음은 두 번째 테이블이 선호하는 세 번째 테이블의 정보로 테이블을 업데이트 할 수 있도록합니다.

UPDATE t1
LEFT JOIN
 t2
ON 
 t2.some_id = t1.some_id
LEFT JOIN
 t3 
ON
 t2.t3_id = t3.id
SET 
 t1.new_column = t3.column;

이것은 사용자와 그룹이 있고 사용자가 그룹 이름의 고유 한 변형을 추가 할 수 있도록하려는 경우에 유용합니다. 따라서 원래 그룹 이름을 사용자가있는 필드로 가져 오려고합니다. 그것을 수정할 수있을 것입니다.


4
Table A 
+--------+-----------+
| A-num  | text      | 
|    1   |           |
|    2   |           |
|    3   |           |
|    4   |           |
|    5   |           |
+--------+-----------+

Table B
+------+------+--------------+
| B-num|  date        |  A-num | 
|  22  |  01.08.2003  |     2  |
|  23  |  02.08.2003  |     2  | 
|  24  |  03.08.2003  |     1  |
|  25  |  04.08.2003  |     4  |
|  26  |  05.03.2003  |     4  |

표 A의 필드 텍스트를

UPDATE `Table A`,`Table B`
SET `Table A`.`text`=concat_ws('',`Table A`.`text`,`Table B`.`B-num`," from                                           
",`Table B`.`date`,'/')
WHERE `Table A`.`A-num` = `Table B`.`A-num`

이 결과를 얻으십시오.

Table A 
+--------+------------------------+
| A-num  | text                   | 
|    1   |  24 from 03 08 2003 /  |
|    2   |  22 from 01 08 2003 /  |       
|    3   |                        |
|    4   |  25 from 04 08 2003 /  |
|    5   |                        |
--------+-------------------------+

여기서 표 B의 하나의 필드 만 허용되지만이 결과가 나옵니다.

Table A 
+--------+--------------------------------------------+
| A-num  | text                                       | 
|    1   |  24 from 03 08 2003                        |
|    2   |  22 from 01 08 2003 / 23 from 02 08 2003 / |       
|    3   |                                            |
|    4   |  25 from 04 08 2003 / 26 from 05 03 2003 / |
|    5   |                                            |
+--------+--------------------------------------------+

0
UPDATE `Table A` a
SET a.`text`=(
        SELECT group_concat(b.`B-num`,' from ',b.`date` SEPARATOR ' / ') 
        FROM `Table B` b WHERE (a.`A-num`=b.`A-num`)
)

-1
                DECLARE @cols VARCHAR(max),@colsUpd VARCHAR(max), @query VARCHAR(max),@queryUpd VARCHAR(max), @subQuery VARCHAR(max)
DECLARE @TableNameTest NVARCHAR(150)
SET @TableNameTest = @TableName+ '_Staging';
SELECT  @colsUpd = STUF  ((SELECT DISTINCT '], T1.[' + name,']=T2.['+name+'' FROM sys.columns
                 WHERE object_id = (
                                    SELECT top 1 object_id 
                                      FROM sys.objects
                                     WHERE name = ''+@TableNameTest+''
                                    )
                and name not in ('Action','Record_ID')
                FOR XML PATH('')
            ), 1, 2, ''
        ) + ']'


  Select @queryUpd ='Update T1
SET '+@colsUpd+'
FROM '+@TableName+' T1
INNER JOIN '+@TableNameTest+' T2
ON T1.Record_ID = T2.Record_Id
WHERE T2.[Action] = ''Modify'''
EXEC (@queryUpd)

3
답변을 더 유용하게하려면 설명을 추가하십시오!
namezero
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.