문제

나는 알고 삽입할 수 있는 여러 행에는 일단 방법이 있을 업데이트를 여러 행에 한 번(에서와 같이,하나의 쿼리로)에서 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...에 복제 키 업데이트합니다.

를 사용하여 예를 들어:

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

다른 팁

했기 때문에 동적인 값을 사용할 필요가 있는 경우 또는 사례에 대한 열 업데이트 할 수 있습니다.그것이해져 가고 못생긴 하지만 작업해야 합니다.

를 사용하여를 들어,당신은 그것을 할 수 있습 다음과 같:

UPDATE table SET Col1 = CASE id 
                          WHEN 1 THEN 1 
                          WHEN 2 THEN 2 
                          WHEN 4 THEN 10 
                          ELSE Col1 
                        END, 
                 Col2 = CASE id 
                          WHEN 3 THEN 3 
                          WHEN 4 THEN 12 
                          ELSE Col2 
                        END
             WHERE id IN (1, 2, 3, 4);

문제는 오직 나를 확장하는 주제와는 다른 대답이다.

내 포인트는 가장 쉬운 방법은 그것을 달성하기 위해 단지를 랩으로 여러 쿼리를 수 있습니다.허용된 응답 INSERT ... ON DUPLICATE KEY UPDATE 좋은 해킹,그러나 알고 있어야 하는 단점과 제한사항:

  • 되는 것으로 말하면 일을 시작하는 쿼리와 행의 기본 키가 존재하지 않에 테이블을 쿼리를 삽입하는 새로운"half-baked"기록합니다.아마도 그것은 당신이 무엇을 원
  • 테이블이 있는 경우으로 null 이 아닌 필드없이 기본값이고 싶지 않아요 이 분야에서 쿼리,당신을 얻을 것 "Field 'fieldname' doesn't have a default value" MySQL 경고를 하지 않는 경우에 삽입하는 단 하나 줄에 모두.그것이 문제가 당신을 얻을,당신이 할 것을 결정하는 경우 엄격하고 돌 mysql 경고로 런타임 예외에서의 응용이다.

제가 몇 가지 성능 테스트의 세 가지 제안된 변형을 포함 INSERT ... ON DUPLICATE KEY UPDATE 변형,변형으로"케이스//때 그런 다음"절하고 순진한 방법으로 트랜잭션이 있습니다.당신이 얻을 수 있습니다 python 코드 및 결과 .전반적인 결론은 변형 케이스에 문의 것으로 밝혀졌으로 두 배 빠른 속도로 다른 두 개 있지만,그것은 매우 열심히 쓰는 정확하고 사출 안전한 코드에 대한 그것은,그래서 개인적으로 스틱을하는 가장 간단한 방법:를 사용하여 트랜잭션이 있습니다.

편집: 연구 결과의 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 가지 방법이 중요합니다.

3methods:

  1. 하려면:면에 복제 키 업데이트
  2. 트랜잭션:어디에 당신 업데이트 각 레코드에 대한 트랜잭션 내에서
  3. 경우:는 경우/경우 각각 다른 기록 내에서 업데이트

나는 그냥 시험이,그리고 삽입하는 방법 6.7x 보다 나를 더 빨리 거래 방법입니다.를 즐길 수 있는 빠르고 편리한 방법을 설정 모두 3,000 30,000 행이 있습니다.

거래 방법은 여전히 실행하는 각 개별적으로 쿼리 시간이 걸리지만,일괄 처리 결과를 메모리에,또는 동안 실행됩니다.거래 방법은 또한 꽤 비싼 모두에 복제 및 쿼리를 기록합니다.

심지어 경우 방법 ×41.1 보다 느리게 삽입하는 방법 w/30,000 레코드(6.1x 보다 느린 트랜잭션).고 75x 느린에 MyISAM.삽입 및 케이스 방법도에서~1,000 기록합니다.에서도 100 레코드 케이스는 방법이 간신히 빠르다.

그래서 일반적으로,나는 느낌을 삽입하는 방법은 모두 최고 쉬운 사용합니다.쿼리를 작고 쉽게 읽기만을 1 쿼리의 작업입니다.이 모두 적용됩니다 InnoDB 및 MyISAM.

보너스 재료:

에 대한 솔루션을 삽입하는 기본값이 아닌 필드를 일시적으로 끄는 관련 SQL 모드: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TA‌​BLES",""),"STRICT_AL‌​L_TABLES","").는지 확인을 저장할 sql_mode 먼저 계획인 경우에으로 복귀습니다.

에 대한 의견을 나는 본 적이 말하는 다음의 특징을 간를 사용하여 삽입하는 방법으로,나이는 너무 그리고 그것은 보인다되지 않습니다.

코드를 실행하는 테스트는 다음과 같습니다.그것은 또한 출력이 있습니다.SQL 파일을 제거하 php 통역의 오버헤드

<?
//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;

또한,그것은 보이는 것이 분명할 수도 있습니다 업데이트를 다른 테이블에서뿐만 아니라.이 경우,업데이트로 선택""문을 제공,당신은 테이블에서 데이터를 지정됩니다.당신이 명시적으로 쿼리에서 업데이트 값 그래서 두 테이블은 영향을 받지 않습니다.

왜 아무도 언급 여러 문에서 하나 쿼리?

Php 에서 사용 multi_query 방법 mysqli 인스턴스입니다.

php 설명서

MySQL 선택적으로 허용하는 데는 여러 문이 하나의 문에서 문자열입니다.보내는 여러 문을 한 번에 감소하는 클라이언트-서버 라운드 여행은 그러나 필요한 특별한 처리가 있습니다.

결과는 다음과 같습니다 비교하는 다른 3 가지 방법을 업데이트 30,000 원.코드 찾을 수 있습니다 을 기반으로 응답에서@Dakusan

트랜잭션:5.5194580554962
하려면:0.20669293403625
경우:16.474853992462
Multi:0.0412278175354

당신이 볼 수 있듯이,여러 문 쿼리를 보다 더 효율적인 최고 대답합니다.

만약 당신이이 같은 오류 메시지:

PHP Warning:  Error while sending SET_OPTION packet

필요할 수 있는 증가 max_allowed_packet mysql config 파일에서 내 컴퓨터 /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 는 주요한 독특한 열쇠
  • 당신이 사용하는 경우 외국 열쇠 표를 참조,교체 삭제 삽입한 후,그래서 이것도 오류가 발생

다음 업데이트됩니다 모든 행에서 한 테이블

Update Table Set
Column1 = 'New Value'

다음 중 하나이 업데이트됩니다 모든 행의 값 Column2 보다 더 5

Update Table Set
Column1 = 'New Value'
Where
Column2 > 5

Unkwntech's 를 들어의 업데이트 하나 이상의 테이블

UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'

그리고 그것은 사용하여 가능한 삽입에 복제 키 업데이트 sql 문..syntax:에 삽입 table_name(a,b,c)값(1,2,3),(4,5,6) 에 복제 키 업데이트=값(a),b=값(b),c=값(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'

이해 당신은'r 찾고 있습니다.다만 더 추가한다.나는 그것을 테스트했습니다.

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

업데이트할 수 있도록 구멍이 하나인 테이블을 쿼리

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top