Vra

Ek weet dat jy kan voeg verskeie rye op een slag, is daar'n manier om te werk verskeie rye in'n keer (soos in, in een navraag) in MySQL?

Edit:Byvoorbeeld ek het die volgende

Name   id  Col1  Col2
Row1   1    6     1
Row2   2    2     3
Row3   3    9     5
Row4   4    16    8

Ek wil om te meng al die volgende Updates in een navraag

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;
Was dit nuttig?

Oplossing

Ja, dit is moontlik -. Jy kan plaas gebruik ... OP duplikaatsleutel UPDATE

Die gebruik van jou voorbeeld:

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

Ander wenke

Aangesien jy dinamiese waardes, moet jy 'n IF of CASE gebruik vir die kolomme word opgedateer. Dit raak kinda lelik, maar dit moet werk.

Die gebruik van jou voorbeeld, kan jy doen dit graag:

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

Die vraag is oud, maar ek wil graag uit te brei die onderwerp met'n ander antwoord.

My punt is, die maklikste manier om dit te bereik, is net om te draai verskeie navrae met'n transaksie.Die aanvaarde antwoord INSERT ... ON DUPLICATE KEY UPDATE is'n mooi hack, maar'n mens moet bewus wees van sy nadele en beperkings:

  • Soos gesê, as jy gebeur om te begin die soektog met rye wie se primêre sleutels nie bestaan in die tabel, die navraag insetsels nuwe "half-gebakte" rekords.Waarskynlik dit is nie wat jy wil hê
  • As jy het'n tafel met'n nie null veld sonder die standaard waarde en wil nie aan te raak hierdie veld in die soektog, jy sal kry "Field 'fieldname' doesn't have a default value" MySQL waarskuwing selfs as jy nie voeg'n enkele ry op alle.Dit sal kry jy in die moeilikheid, as jy besluit om te wees streng en draai mysql waarskuwings in runtime uitsonderings in jou app.

Ek het'n paar prestasie toetse vir drie van die voorgestelde weergawes, insluitend die INSERT ... ON DUPLICATE KEY UPDATE variant, 'n variant met "geval / wanneer / dan" klousule en'n naïewe benadering met die transaksie.Jy kan kry die luislang kode en resultate hier.Die oorhoofse gevolgtrekking is dat die variant met die geval verklaring blyk te wees twee keer so vinnig as die ander twee variante, maar dit is baie moeilik om te skryf die korrekte en inspuiting-veilige kode vir dit, so ek persoonlik hou by die eenvoudigste benadering:met behulp van die transaksies.

Edit: Bevindinge van Dakusan bewys dat my prestasie skattings is nie heeltemal geldig nie.Sien asseblief hierdie antwoord vir'n ander, meer uitgebreide navorsing.

Nie seker hoekom ander nuttige opsie nog nie genoem word:

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;

Al die volgende is van toepassing op InnoDB.

Ek voel om te weet die spoed van die 3 verskillende metodes is belangrik.

Daar is 3 maniere:

  1. INSERT: Plaas met OP duplikaatsleutel UPDATE
  2. TRANSAKSIE: Waar jy 'n update vir elke rekord te doen binne 'n transaksie
  3. CASE: In watter jy 'n saak / wanneer vir elke verskillende rekord in 'n UPDATE

Ek het nou net hierdie getoets, en die insetsel metode was 6.7x vinniger vir my as die transaksie metode. Ek het probeer om op 'n stel van beide 3000 en 30.000 rye.

Die transaksie metode moet nog elke hardloop individueel navraag, wat tyd neem, al is dit die resultate in die geheue, of iets groepe, terwyl die uitvoering van. Die transaksie metode is ook redelik duur in beide replikasie en navraag logs.

Erger nog, die geval metode was 41.1x stadiger as die insetsel metode w / 30.000 rekords (6.1x stadiger as transaksie). En 75x stadiger in MyISAM. INSERT en CASE metodes gebreek selfs op ~ 1000 rekords. Selfs teen 100 rekords, die geval metode is skaars vinniger.

So in die algemeen, ek voel die insetsel metode is beide die beste en maklikste om te gebruik. Die navrae is kleiner en makliker om te lees en neem slegs 1 navraag van aksie. Dit geld vir beide InnoDB en MyISAM.

Bonus dinge:

Die oplossing vir die insetsel nie-standaard-veld probleem is om die betrokke SQL modes tydelik afskakel: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TA‌​BLES",""),"STRICT_AL‌​L_TABLES",""). Maak seker dat jy die sql_mode eerste as jy van plan bespaar op terugkeer nie.

As vir ander kommentaar wat ek gesien het wat sê die auto_increment styg met behulp van die insetsel metode, getoets Ek dit ook en dit blyk die geval te wees nie.

Kode om die toetse uit te voer, is soos volg. Wat dit uitset ook .SQL lêers te php tolk oorhoofse verwyder

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

Dit behoort te werk vir ya.

Daar is 'n verwysing in die MySQL handleiding vir verskeie tafels.

Gebruik 'n tydelike tabel

// 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`");
}

Jy kan dieselfde tabel alias vir jou gee die ID's wat jy wil voeg by (as jy doen 'n ry-deur-ry update:

UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET 
col1 = 1
,col2 = 2
. . . 
WHERE 
tab1.id = tab2.id;

Verder moet dit voor die hand liggend dat jy ook kan werk uit ander tafels sowel lyk. In hierdie geval, die update verdubbel as 'n "Kies" verklaring, gee jy die data in die tabel wat jy spesifiseer. Jy is uitdruklik verklaar in jou navraag die update waardes so, die tweede tafel is onaangeraak.

Waarom niemand noem verskeie state in een navraag ?

In php, gebruik jy multi_query metode van mysqli byvoorbeeld.

Van die PHP handleiding

  

MySQL opsioneel kan met verskeie state in een verklaring string. verskeie state te stuur in 'n keer verminder kliënt-bediener ronde reise maar vereis 'n spesiale hantering.

Hier is die resultaat in vergelyking met ander 3 metodes in update 30000 rou. Kode kan gevind hier wat gebaseer is op antwoord uit @Dakusan

transaksie: 5,5194580554962
Voeg: ,20669293403625
Geval: 16,474853992462
Multi: ,0412278175354

Soos jy kan sien, verskeie stellings navraag is meer doeltreffend as die hoogste antwoord.

As jy fout boodskap soos hierdie:

PHP Warning:  Error while sending SET_OPTION packet

Jy mag nodig wees om die max_allowed_packet in mysql opstelling lêer, wat in my masjien is /etc/mysql/my.cnf verhoog en dan weer te begin mysqld.

Jy kan ook belangstel in die gebruik van aansluit op updates, wat moontlik ook wees.

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.

Edit:. As die waardes wat jy wil bywerk nie afkomstig is van 'n ander plek in die databasis, moet jy verskeie update navrae uit te reik

Daar is 'n instelling wat jy kan verander die naam "multi verklaring 'dat MySQL se" veiligheid meganisme' geïmplementeer om te verhoed dat (meer as een) inspuiting opdrag versper. Tipiese om 'n briljante "implementering MySQL se, is dit ook verhoed dat gebruikers van doen doeltreffende navrae.

Hier ( http: // dev. mysql.com/doc/refman/5.1/en/mysql-set-server-option.html ) is 'n paar inligting oor die C implementering van die omgewing.

As jy met behulp van PHP, jy kan mysqli gebruik om multi state doen (ek dink php het verskeep met mysqli vir 'n rukkie nou)

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

Hoop dit help.

gebruik

REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);

Let op:

  • id moet 'n primêre unieke sleutel wees
  • As jy vreemde sleutels te gebruik verwys na die tafel, die plek uitvee dan insetsels, so dit kan veroorsaak 'n fout

Die volgende sal alle rye te werk in 'n tabel

Update Table Set
Column1 = 'New Value'

Die volgende een sal alle rye waar die waarde van COLUMN2 is meer as 5

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

Daar is al Unkwntech se voorbeeld van die opdatering van meer as een tabel

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

Wil ..it is moontlik met behulp van insetsel oor duplikaatsleutel UPDATE SQL-stelling .. sintaksis: Voeg in table_name (a, b, c) WAARDES (1,2,3), (4,5,6)     OP duplikaatsleutel UPDATE n = WAARDES (a), b = WAARDES (b), c = WAARDES (c)

Met PHP het ek hierdie. Gebruik kommapunt, verdeel dit in verskeidenheid en dan in te dien via lus.

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

Dit moet bereik wat u profiel pas op soek na. voeg net meer id se. Ek het dit getoets.

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

// Jy moet net die bou van dit in PHP soos

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

Jy gat tafel kan werk met 'n navraag

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top