INSERT INTO ... ON DUPLICATE UPDATE, ale co když nechceme, aby se nový záznam vytvořil, ale jen upravil existující?

Určitě často využíváte funkce ON DUPLICATE UPDATE, já tedy ano. Ušetří to hodně času a dovolí to podle unikátního identifikátoru upravit sadu řádků jedním dotazem.


Například máte sadu záznamů s párovými klíči, v praxi to může být seznam identifikátorů produktů a k tomu ceny v databázi dbf, csv, xml souboru nebo jiným způsob uložené mimo databázi.

Například máme databázi uživatelů a potřebujeme upravit jejich kredit, pomocí tohoto dotazu:

  1. INSERT INTO uzivatele (id_uzivatel, kredit) VALUES (1, 100), (2, 150), (10, 300) ON DUPLICATE KEY UPDATE kredit=VALUES(kredit);

Ovšem může se stát, že nechcete, aby při neexistenci unikátního identifikátoru (id_uzivatel) byl nový uživatel vložen.

Já to řeším dočasnou tabulkou a sadou dotazů, takto:

  1. $q = "CREATE TEMPORARY TABLE `temp_uzivatele` (
  2. `id_uzivatel` INT(11) NOT NULL,
  3. `kredit` INT(11) NOT NULL,
  4. PRIMARY KEY (`id_uzivatel`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;";
  6. if (!$sql->query($q)) throw new Exception("Nepodařilo se vytvořit dočasnou tabulku.");
  7.  
  8. $ins=array("(1,100)","(2,150)","(10,300)"); // pochopitelně toto pole je vytvořeno v nějakém cyklu, který prochází csv, dbf, xml nebo jiný typ uložených dat
  9.  
  10. $q="INSERT INTO temp_uzivatele (id_uzivatel, kredit) VALUES ".implode(",", $ins).";";
  11. if (!$sql->query($q)) throw new Exception("Nepodařilo se naplnit dočasnou tabulku.");
  12. $q="UPDATE uzivatele u JOIN temp_uzivatele tu ON (u.id_uzivatel=tu.id_uzivatel) SET u.kredit=tu.kredit;";
  13. if (!$sql->query($q)) throw new Exception("Nepodařilo se upravit data z dočasné tabulky.");

Co vy nato? Nějaký lepší způsob nebo přístup?

podobné články

24.01.2009Jeden dotaz do databáze nebo tisíce? ... je to stejné?(88%)
24.02.2009MSSQL UPSERT, INSERT INTO ... ON DUPLICATE KEY UPDATE(13%)

komentáře

RSS Komentáře k článku RSS Komentáře   Add to Google
08.12.2008 17:19 | Anonym (v6ak) | Výjimky

Nevím, co používáš k databázím, ale pokud PDO, tak tam se dá nastavit, aby používalo výjimky a není nutné dělat šílenosti typu if (!$sql->query($q)) throw new …

08.12.2008 20:36 | Administrátor | Re: Výjimky
  1. díky za názor, trochu offtopic, takže rád podívám na článek, který popisuje co říkáš a rozvedeme diskusi tma
  2. PDO nepoužívám, mám vlastní framework, umí také nějakým způsobem pracovat s vyjímkami, ale tohle mi vyhovuje, jak předáš zprávu vyjímce v PDO?
11.01.2009 00:26 | Anonym (Miloslav Ponkrác) | Použiji normální SQL

Nechci-li vložit záznam, pouze upravit, používá se odjakživa UPDATE SQL příkaz. K tomu slouží, sloužil a sloužit bude. Po vykonání příkazu UPDATE lze přečíst počet změněných řádků a zjistit, zda vůbec se našel záznam, který bylo možné změnit.

Stačí nehledat exotická řešení a použít naprosté databázové základy.

Miloslav Ponkrác

11.01.2009 09:47 | Administrátor | Re: Použiji normální SQL

napište analogické použití s update

11.01.2009 13:31 | Anonym (Miloslav Ponkrác) | UPDATE

Jednoduše pošlu více příkazů UPDATE.

A kdybych už chtěl nutně z toho udělat jeden UPDATE, napíšu:

UPDATE tabulka SET pole= (CASE WHEN id_uzivatel=1 THEN 100 WHEN id_uzivatel=2 THEN 150 WHEN id_uzivatel=10 THEN 300 END) WHERE id_uzivatel IN(1,2,300)

Miloslav Ponkrác

11.01.2009 21:12 | Administrátor | Re: UPDATE

a co myslíte, že bude méně zatěžující pro server a rychleji provedené? mne přijde vaše řešení nereálné v mnoha situacích a hlavně složitější, opravdu existují projekty, kde na tom záleží a pokud si máte vybrat mezi zpracováním za 15minut nebo za 30 sekund volba je jasná, teď si jen říkám, že ta kniha o mysql, kde autor je jmenovec to je shoda jmen, že?

22.01.2009 21:52 | Anonym (Miloslav Ponkrác) | UPDATE

Bude to úplně stejně zatěžující, pokud to dobře napíšete, protože to vnitřně dělá naprosto to samé, co ten Váš INSERT INTO…

Nicméně nechápu, proč se bojíte více UPDATE příkazů. To, jestli pošlete jeden SQL příkaz, nebo padesát naprosto nic neříká o rychlosti, s jakou to databáze provede.

Jinak živím se databázemi už dvacet let, a bývával jsem krizovým člověkem – člověkem, který řešil problémy, když už databáze padala výkonově na ústa, a bylo potřeba z ní ještě vymáčknout něco, případně jakékoli jiné problémy, se kterým si běžní profesionální databázisté nevědí rady.

MySQL jsem mimochodem administroval na starém dnes již zaniklém DC hubu CZECHANNEL PRO, kde jsem musel uchodit naráz kolem 10 tisíc uživatelů nad ní. MySQL pracovala opravdu na hraně toho co dokázala.

Proč to říkám? Možná proto, abych Vám řekl, zbavte se mýtů ohledně databází a SQL dotazů. A první mýtus je, že jeden SQL dotaz musí být nutně rychlejší, než série SQL dotazů. Nemusí. Parsování SQL dotazu je naprosto zanedbatelně náročné pro databáze oproti jeho zpracování.

A ohýbat dotaz typu INSERT pro akce, které má ve skutečnosti dělat UPDATE a pak hlídat, aby to náhodou neudělalo to co má INSERT dělat – to je neskutečná volovina. Řekl bych to ostřeji, ale mám úctu k lidem jako jste Vy, kteří nad věcmi přemýšlejí, a snaží se dělat věci tak, aby to optimálně fungovalo.

24.01.2009 00:20 | Administrátor | Re: UPDATE

nemohu si pomoci, ale při větším množství updatů se operace neuvěřitelně a nepoměrně zpomalí, zajímalo by mne jak se něco takového dá optimalizovat, rozdíly jsou v desítkách minut

23.01.2009 21:28 | Anonym (Miloslav Ponkrác) | Kniha

„kniha o mysql, kde autor je jmenovec to je shoda jmen“

Ne, tu jsem napsal já. :-)

24.01.2009 02:46 | Administrátor | Re: Kniha

rozšířil jsem tuto úvahu o další článek a uvedl nějaký test http://www.webfaq.cz/…je-to-stejne

Jméno
Název
Text
Lze používat Texy! syntax. Příklad syntaxe: "text odkazu":odkaz, **tučně**, *kurzíva*, `code`. PHP kód uzavírejte do <?php ... ?> a JavaScript do <script> ... </script>