MySQL의 여러 업데이트
한 번에 여러 행을 삽입 할 수 있다는 것을 알고 있습니다 .MySQL에서 한 번에 여러 행을 한 번에 업데이트 할 수 있습니까?
편집 : 예를 들어 다음이 있습니다.
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
다음 업데이트를 모두 하나의 쿼리로 결합하고 싶습니다.
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
예, 가능합니다-중복 키 업데이트에 INSERT ... ON을 사용할 수 있습니다.
귀하의 예를 사용하여 :
INSERT INTO table (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);
동적 값이 있으므로 열을 업데이트하려면 IF 또는 CASE를 사용해야합니다. 좀 못 생겼지 만 작동해야합니다.
예제를 사용하면 다음과 같이 할 수 있습니다.
업데이트 테이블 SET Col1 = CASE id 1시 1시 2시 2시 4시 10시 ELSE Col1 종료, Col2 = CASE id 3시 3시 4시 12시 ELSE Col2 종료 id IN (1, 2, 3, 4);
질문은 오래되었지만 다른 답변으로 주제를 확장하고 싶습니다.
내 요점은 그것을 달성하는 가장 쉬운 방법은 트랜잭션으로 여러 쿼리를 래핑하는 것입니다. 허용되는 대답 INSERT ... ON DUPLICATE KEY UPDATE
은 좋은 해킹이지만 단점과 한계를 알고 있어야합니다.
- 말했듯이, 기본 키가 테이블에 존재하지 않는 행으로 쿼리를 시작하면 쿼리는 새로운 "반 베이크"레코드를 삽입합니다. 아마도 그것은 당신이 원하는 것이 아닐 것입니다
- 기본값이없는 null이 아닌 필드가있는 테이블이 있고 쿼리 에서이 필드를 터치하지 않으려는
"Field 'fieldname' doesn't have a default value"
경우 단일 행을 전혀 삽입하지 않아도 MySQL 경고가 표시됩니다. 엄격하고 mysql 경고를 앱의 런타임 예외로 설정하면 문제가 발생할 수 있습니다.
INSERT ... ON DUPLICATE KEY UPDATE
변형, "case / when / then"절이있는 변형 및 트랜잭션에 대한 순진한 접근을 포함하여 세 가지 제안 된 변형에 대한 성능 테스트를 수행했습니다. 당신은 파이썬 코드와 결과를 얻을 수 있습니다 여기에 . 전반적인 결론은 case 문이있는 변형이 다른 두 변형보다 두 배 빠르다는 것이지만 올바른 코드와 삽입 안전 코드를 작성하는 것은 매우 어렵 기 때문에 개인적으로 가장 간단한 접근법 인 트랜잭션 사용을 고수합니다.
편집 : Dakusan의 결과는 내 성능 평가가 상당히 유효하지 않다는 것을 증명합니다. 보다 정교한 다른 연구에 대해서는 이 답변 을 참조하십시오 .
다른 유용한 옵션이 아직 언급되지 않은 이유는 확실하지 않습니다.
UPDATE my_table m
JOIN (
SELECT 1 as id, 10 as _col1, 20 as _col2
UNION ALL
SELECT 2, 5, 10
UNION ALL
SELECT 3, 15, 30
) vals ON m.id = vals.id
SET col1 = _col1, col2 = _col2;
다음은 모두 InnoDB에 적용됩니다.
세 가지 방법의 속도를 아는 것이 중요하다고 생각합니다.
3 가지 방법이 있습니다 :
- INSERT : ON DUPLICATE KEY UPDATE로 INSERT
- 거래 : 거래 내 각 레코드에 대한 업데이트를 수행하는 경우
- 사례 : UPDATE 내의 각기 다른 레코드에 대한 사례 / 시간
방금 이것을 테스트했으며 INSERT 방법이 TRANSACTION 방법보다 6.7x 빠릅니다. 나는 3,000 행과 30,000 행을 시도했습니다.
TRANSACTION 메서드는 여전히 각 개별 쿼리를 실행해야하지만 실행하는 동안 결과를 메모리 등으로 일괄 처리하지만 시간이 걸립니다. TRANSACTION 방법은 복제 및 쿼리 로그 모두에서 상당히 비쌉니다.
더 나쁜 것은 CASE 방법이 30,000 레코드의 INSERT 방법보다 41.1 배 느리다는 것입니다 (TRANSACTION보다 6.1 배 느림). 그리고 75X 의 MyISAM 느린. INSERT 및 CASE 방법은 ~ 1,000 레코드에서도 끊어졌습니다. 100 개의 레코드에서도 CASE 방법이 엄청나게 빠릅니다.
따라서 일반적으로 INSERT 방법이 가장 좋고 사용하기 쉽다고 생각합니다. 쿼리는 더 작고 읽기 쉬우 며 하나의 쿼리 작업 만 수행합니다. 이것은 InnoDB와 MyISAM 모두에 적용됩니다.
보너스 물건 :
INSERT 비 기본 필드 문제에 대한 해결책은 관련 SQL 모드를 일시적으로 끄는 것 SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
입니다. sql_mode
되돌릴 계획이라면 첫 번째 를 저장하십시오 .
다른 의견에 관해서는 auto_increment가 INSERT 메소드를 사용하여 올라간다고 말한 것을 보았지만 그도 테스트했지만 그렇지 않은 것 같습니다.
테스트를 실행하는 코드는 다음과 같습니다. 또한 PHP 인터프리터 오버 헤드를 제거하기 위해 .SQL 파일을 출력합니다.
<?
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}
UPDATE table1, table2 SET table1.col1='value', table2.col1='value' WHERE table1.col3='567' AND table2.col6='567'
이것은 나중에 작동합니다.
MySQL 매뉴얼 에는 여러 테이블에 대한 참조가 있습니다.
임시 테이블을 사용하십시오.
// Reorder items
function update_items_tempdb(&$items)
{
shuffle($items);
$table_name = uniqid('tmp_test_');
$sql = "CREATE TEMPORARY TABLE `$table_name` ("
." `id` int(10) unsigned NOT NULL AUTO_INCREMENT"
.", `position` int(10) unsigned NOT NULL"
.", PRIMARY KEY (`id`)"
.") ENGINE = MEMORY";
query($sql);
$i = 0;
$sql = '';
foreach ($items as &$item)
{
$item->position = $i++;
$sql .= ($sql ? ', ' : '')."({$item->id}, {$item->position})";
}
if ($sql)
{
query("INSERT INTO `$table_name` (id, position) VALUES $sql");
$sql = "UPDATE `test`, `$table_name` SET `test`.position = `$table_name`.position"
." WHERE `$table_name`.id = `test`.id";
query($sql);
}
query("DROP TABLE `$table_name`");
}
동일한 테이블의 별칭을 지정하여 삽입하려는 ID를 제공 할 수 있습니다 (행별 업데이트를 수행하는 경우).
UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET
col1 = 1
,col2 = 2
. . .
WHERE
tab1.id = tab2.id;
또한 다른 테이블에서도 업데이트 할 수 있음이 분명합니다. 이 경우 업데이트는 "SELECT"문으로 두 배가되어 지정한 테이블의 데이터를 제공합니다. 쿼리에 업데이트 값을 명시 적으로 표시하므로 두 번째 테이블은 영향을받지 않습니다.
왜 하나의 쿼리에서 여러 문을 언급하지 않습니까?
PHP에서는 multi_query
mysqli 인스턴스의 메소드 를 사용 합니다.
보내는 사람 PHP 매뉴얼
MySQL은 선택적으로 하나의 명령문 문자열에 여러 명령문을 허용합니다. 한 번에 여러 명령문을 보내면 클라이언트-서버 왕복이 줄어들지 만 특별한 처리가 필요합니다.
다음은 업데이트 30,000 raw의 다른 3 가지 방법과 비교 한 결과입니다. @Dakusan의 답변을 기반으로 한 코드를 여기 에서 찾을 수 있습니다.
거래 : 5.5194580554962
삽입 : 0.20669293403625
케이스 : 16.474853992462
멀티 : 0.0412278175354
보시다시피 여러 문 쿼리가 가장 높은 답변보다 효율적입니다.
다음과 같은 오류 메시지가 표시되는 경우 :
PHP Warning: Error while sending SET_OPTION packet
max_allowed_packet
내 컴퓨터에있는 mysql 구성 파일 을 증가시킨 /etc/mysql/my.cnf
다음 mysqld를 다시 시작 해야 할 수도 있습니다 .
업데이트시 조인을 사용하는 것도 가능할 수 있습니다.
Update someTable Set someValue = 4 From someTable s Inner Join anotherTable a on s.id = a.id Where a.id = 4
-- Only updates someValue in someTable who has a foreign key on anotherTable with a value of 4.
편집 : 업데이트하는 값이 데이터베이스의 다른 곳에서 나오지 않으면 여러 업데이트 쿼리를 발행해야합니다.
주입 명령을 방지하기 위해 MySQL의 '안전 메커니즘'을 비활성화하는 '다중 명령문'이라는 설정을 변경할 수 있습니다. 일반적으로 MySQL의 '화려한'구현에서 사용자가 효율적인 쿼리를 수행하지 못하게합니다.
여기 ( http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html )는 설정의 C 구현에 대한 정보입니다.
PHP를 사용하는 경우 mysqli를 사용하여 여러 명령문을 수행 할 수 있습니다 (php는 잠시 동안 mysqli와 함께 제공 된 것 같습니다)
$con = new mysqli('localhost','user1','password','my_database');
$query = "Update MyTable SET col1='some value' WHERE id=1 LIMIT 1;";
$query .= "UPDATE MyTable SET col1='other value' WHERE id=2 LIMIT 1;";
//etc
$con->multi_query($query);
$con->close();
희망이 도움이됩니다.
사용하다
REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);
참고 :
- id는 기본 고유 키 여야합니다
- 외래 키를 사용하여 테이블을 참조하면 REPLACE가 삭제 후 삽입되므로 오류가 발생할 수 있습니다.
다음은 한 테이블의 모든 행을 업데이트합니다.
Update Table Set
Column1 = 'New Value'
다음은 Column2의 값이 5보다 큰 모든 행을 업데이트합니다.
Update Table Set
Column1 = 'New Value'
Where
Column2 > 5
둘 이상의 테이블을 업데이트하는 Unkwntech 의 모든 예가 있습니다
UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'
예 .. INSERT ON DUPLICATE KEY UPDATE sql 문을 사용하여 가능합니다. 구문 : INSERT INTO table_name (a, b, c) VALUES (1,2,3), (4,5,6) 중복 키 업데이트시 a = VALUES (a), b = VALUES (b), c = VALUES (c)
PHP로 나는 이것을했다. 세미콜론을 사용하여 배열로 분할 한 다음 루프를 통해 제출하십시오.
$con = new mysqli('localhost','user1','password','my_database');
$batchUpdate = true; /*You can choose between batch and single query */
$queryIn_arr = explode(";", $queryIn);
if($batchUpdate) /* My SQL prevents multiple insert*/
{
foreach($queryIn_arr as $qr)
{
if(strlen($qr)>3)
{
//echo '<br>Sending data to SQL1:<br>'.$qr.'</br>';
$result = $conn->query($qr);
}
}
}
else
{
$result = $conn->query($queryIn);
}
$con->close();
UPDATE tableName SET col1='000' WHERE id='3' OR id='5'
이것은 당신이 찾고있는 것을 달성해야합니다. 더 많은 ID를 추가하십시오. 나는 그것을 테스트했다.
UPDATE `your_table` SET
`something` = IF(`id`="1","new_value1",`something`), `smth2` = IF(`id`="1", "nv1",`smth2`),
`something` = IF(`id`="2","new_value2",`something`), `smth2` = IF(`id`="2", "nv2",`smth2`),
`something` = IF(`id`="4","new_value3",`something`), `smth2` = IF(`id`="4", "nv3",`smth2`),
`something` = IF(`id`="6","new_value4",`something`), `smth2` = IF(`id`="6", "nv4",`smth2`),
`something` = IF(`id`="3","new_value5",`something`), `smth2` = IF(`id`="3", "nv5",`smth2`),
`something` = IF(`id`="5","new_value6",`something`), `smth2` = IF(`id`="5", "nv6",`smth2`)
// 방금 PHP로 빌드
$q = 'UPDATE `your_table` SET ';
foreach($data as $dat){
$q .= '
`something` = IF(`id`="'.$dat->id.'","'.$dat->value.'",`something`),
`smth2` = IF(`id`="'.$dat->id.'", "'.$dat->value2.'",`smth2`),';
}
$q = substr($q,0,-1);
따라서 하나의 쿼리로 구멍 테이블을 업데이트 할 수 있습니다
참고 URL : https://stackoverflow.com/questions/3432/multiple-updates-in-mysql
'Programming' 카테고리의 다른 글
공개적으로 보이는 유형 또는 멤버에 대한 XML 주석이 누락되었습니다. (0) | 2020.02.28 |
---|---|
우분투 12.04의 nodejs와 node (0) | 2020.02.28 |
pandas DataFrame의 열에서 NaN 값을 계산하는 방법 (0) | 2020.02.28 |
브라우저 창 / 탭을 닫을 때 localStorage 항목을 삭제하는 방법은 무엇입니까? (0) | 2020.02.28 |
명령 행에서 특정 Subversion 개정판을 체크 아웃하는 방법은 무엇입니까? (0) | 2020.02.28 |