중복 키의 MySQL-마지막 삽입 ID?


132

다음과 같은 쿼리가 있습니다.

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

삽입 또는 업데이트의 ID를 원합니다. insert_id ()는 업데이트 된 ID가 아닌 '삽입 된'ID 만 반환한다고 생각하기 때문에 일반적으로이를 얻기 위해 두 번째 쿼리를 실행합니다.

두 개의 쿼리를 실행하지 않고 행의 ID를 INSERT / UPDATE하고 검색하는 방법이 있습니까?


3
가정하지 말고 직접 테스트 해 보지 않겠습니까? 위의 편집에서 SQL이 작동하며 테스트를 통해 삽입 실패를 포착하거나 INSERT IGNORE를 사용하거나 복제본이 있는지 먼저 확인하는 것보다 빠릅니다.
Michael Fenwick

4
경고 : 제안 된 솔루션은 작동하지만 삽입이 없어도 auto_increment 값은 계속 증가합니다. 중복 키가 자주 발생하는 경우 alter table tablename AUTO_INCREMENT = 0;id 값에서 큰 차이를 피하기 위해 위 쿼리 이후 에 실행할 수 있습니다.
Frank Forte

답변:


175

이 페이지를 확인하십시오 : https://web.archive.org/web/20150329004325/https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
페이지 하단 MySQL 함수에 표현식을 전달하여 업데이트에 LAST_INSERT_ID를 의미있게 만드는 방법을 설명합니다.

MySQL 문서 예제에서 :

테이블에 AUTO_INCREMENT 열이 있고 INSERT ... UPDATE가 행을 삽입하면 LAST_INSERT_ID () 함수는 AUTO_INCREMENT 값을 반환합니다. 명령문이 대신 행을 업데이트하면 LAST_INSERT_ID ()는 의미가 없습니다. 그러나 LAST_INSERT_ID (expr)를 사용하여이 문제를 해결할 수 있습니다. id가 AUTO_INCREMENT 열이라고 가정하십시오. 업데이트에 LAST_INSERT_ID ()를 의미있게 만들려면 다음과 같이 행을 삽입하십시오.

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

2
어떻게 든 그 페이지를 볼 때 그것을 놓쳤다. 따라서 업데이트 부분은 다음과 같이 나타납니다. UPDATE id = LAST_INSERT_ID (id) 그리고 그것은 훌륭하게 작동합니다. 감사!
thekevinscott

7
php 함수 mysql_insert_id ()는 두 경우 모두 올바른 값을 반환 한다고 합니다 : php.net/manual/en/function.mysql-insert-id.php#59718 .
jayarjo

2
@PetrPeller-글쎄, MySQL 내부를 보지 않고 값을 생성한다는 것을 의미하지만 그 값은 방금 실행 한 쿼리와 관련이 없습니다. 즉, 디버깅하기 어려운 문제입니다.
Jason

13
5.1.12 이후 이것은 더 이상 필요하지 않을 것으로 예상되지만 오늘은 예외가 발견되었습니다. 자동 증분 pk가 있고 전자 메일 주소와 같은 고유 키가 있고 전자 메일 주소를 기반으로 '중복 업데이트'가 트리거되는 경우 last_insert_id '는 업데이트 된 행의 자동 증분 값이 아닙니다. 가장 최근에 삽입 된 자동 증분 값인 것 같습니다. 이것은 큰 차이를 만듭니다. 해결 방법은 여기에 표시된 것과 동일합니다. 즉, 업데이트 쿼리에서 id = LAST_INSERT_ID (id)를 사용합니다.
sckd September

1
5.5에서 @sckd의 의견은 여전히 ​​사실입니다.
e18r

37

정확히 말하면 이것이 원래 쿼리 인 경우 :

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

그리고 'id'는 자동 증가 기본 키이며 이것이 작동하는 솔루션입니다.

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

여기 모두 있습니다 : http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

테이블에 AUTO_INCREMENT 열이 있고 INSERT ... UPDATE가 행을 삽입하면 LAST_INSERT_ID () 함수는 AUTO_INCREMENT 값을 반환합니다. 명령문이 대신 행을 업데이트하면 LAST_INSERT_ID ()는 의미가 없습니다. 그러나 LAST_INSERT_ID (expr)를 사용하여이 문제를 해결할 수 있습니다. id가 AUTO_INCREMENT 열이라고 가정하십시오.


7
예, 당신이 말한 것과 같은 대답을보십시오. 3 살짜리 게시물을 소생시킬 필요가 없습니다. 어쨌든 노력해 주셔서 감사합니다.
fancyPants 2009 년

1
@ tombom이 답변을 게시 한 유일한 이유는 허용 된 답변이 정확하지 않기 때문입니다. 업데이트 할 것이 없으면 작동하지 않습니다.
Aleksandar Popovic

2

레코드가 존재하는 경우 본질적으로 삭제 / 삽입 인 REPLACE를 볼 수 있습니다. 그러나 이렇게하면 자동 증분 필드가 변경되어 다른 데이터와의 관계가 손상 될 수 있습니다.


1
아 그래-나는 이전 ID를 제거하지 않을 무언가를 찾고 있습니다
thekevinscott

제약 조건에 따라 다른 관련 데이터가 삭제 될 수도 있으므로 위험 할 수도 있습니다.
서지


1

ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID (id)가 기본 키를 1 씩 증가시킬 때 문제가 발생했습니다. 따라서 세션 내 다음 입력의 ID는 2 씩 증가합니다.


0

주목할 가치가 있으며, 이것은 새 데이터를 삽입하기 전에 REPLACE가 기존의 일치하는 행을 날려 버릴 것입니다. DUPLICATE KEY UPDATE시 지정한 열만 업데이트하고 행을 유지합니다.

로부터 수동 :

REPLACE는 테이블의 이전 행이 PRIMARY KEY 또는 UNIQUE 인덱스의 새 행과 동일한 값을 갖는 경우 새 행이 삽입되기 전에 이전 행이 삭제된다는 점을 제외하고는 INSERT와 똑같이 작동합니다.


0

자동 증가를 사용하면 기존 솔루션이 작동합니다. 사용자가 접두사를 정의 할 수 있고 3000에서 시퀀스를 다시 시작 해야하는 상황이 있습니다.이 다양한 접두사 때문에 자동 증가를 사용할 수 없으므로 삽입에 대해 last_insert_id가 비어 있습니다. 나는 다음과 같이 해결했다.

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
SELECT LAST_INSERT_ID();

접두사가 있으면 접두사가 증가하고 last_insert_id가 채워집니다. 접두사가없는 경우 접두사는 값 3000으로 접 두부를 삽입하고 last_insert_id를 3000으로 채 웁니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.