Získání celého výsledku v PDO

Školení, která pořádám

Při práci s databází často potřebuji načíst celý výsledek dotazu do pole. Někdy potřebuji všechny sloupce, někdy jenom jeden a někdy se hodí načíst do klíče pole jeden sloupec (např. ID) a do hodnoty jiný (třeba proto, aby se z pole dal vytvořit výběrový seznam). Pro extenzi MySQL jsem si k tomu vytvořil jednoduchou funkci, v PDO je tato funkce k dispozici rovnou:

<?php
// načtení všech řádek do pole asociativních polí
$result->fetchAll(PDO::FETCH_ASSOC);

// načtení samotných hodnot z prvního sloupce
$result->fetchAll(PDO::FETCH_COLUMN);

// načtení prvního sloupce do klíče a druhého do hodnoty pole
$result->fetchAll(PDO::FETCH_KEY_PAIR);
?>

První příkaz je potřeba jen výjimečně, protože výsledkem lze ve foreach cyklu procházet rovnou.

Jakub Vrána, Dobře míněné rady, 5.12.2008, diskuse: 10 (nové: 0)

Diskuse

toby:

Já jsem si naopak zvykl používat fetchAll(PDO::FETCH_ASSOC) poměrně často.
U mysql s nebufferovanými dotazy (což je výchozí chování) totiž nelze pracovat s více dotazy současně. A pak třeba kód:

<?php foreach($db->query($q) as $r) $db->query($q2); ?>

lehne na chybě "Cannot execute queries while other unbuffered queries are active". Stejnou paseku to dělá v metodách při použití "return $stmt->fetch();". To pak radši použiju

<?php function foo() { ...; foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) return $r; } ?>

Je to bezpečnější řešení a má menší režii, než použití bufferovaných dotazů.

ikona Jakub Vrána OpenID:

Máš to "menší režii" podložené nějakými testy? Určitě to bude paměťově méně náročné, ale ve většině případů to bude pomalejší, protože při bufferování se všechna data pošlou najednou, takže se posílá míň paketů, kdežto po jednom řádku se komunikuje víc.

toby:

Ano, myslel jsem paměťovou náročnost. S tou síťovou komunikací máš ovšem pravdu, zvlásť když je db na jiným stroji.

marau:

Zdar, já sem si pro svuj celkem slušný db layer napsal nadstavbu, která mi umožňuje jít ještě dál:

<?php

$lide
= ADBL::dbh()->execute("SELECT kraj_id as _key, mesto_id as _key2, ulice_id as _key3, jmeno, prijmeni")->fetchall_skey_assoc();
?>

pak když chci zjistit třeba všechny uživatele, kteří žijí ve středočeskym kraji -> v Benešově -> v Tyršově ulici tak mám jen třeba

<?php $vysledek = $lide[1][4][2]; ?>

Sice byla celkem fuška napsat to tak aby mi to třeba při 100 000 řádcích nepadalo na max_execution_time ale povedlo se a já si to teď nemůžu vynachválit

?>

Juraj:

Ahoj, tá tvoja nadstavba vyzerá zaujímavo. Dá sa k nej nejakým zázračným spôsobom legálne dostať? :o)

marau:

No zatim ne ale v budoucnu plánuju jeho vydání, mám v tom db layeru ještě více fičůrek a pořad to ještě zdokonaluju, teď ještě dodělávám přidání subklíčů a větvení tak, abych si mohl výsledek naformátovat do pole jak chci, je to ale celkem náročný na výpočetní dobu takže ještě zvážim, jestli to tam dám, asi ne přímo do metody fetchall_skey_assoc() ale do jiný a budu používat na selecty, kde se nevrací tolik řádků.

ikona David Grudl:

Viz http://phpfashion.com/temer-v-cili-dibi-0-9b, hledej "fetchAssoc".

marau:

Hele to je přesně ono co mám já akorát já to definuju přímo v dotazu pomocí aliasů - jeden příklad za všechny

<?php
$records
= ADBL::dbh()->prepare("SELECT user_id as _key, name as _k2v_name, sname as _k2v2_sname, order_id as _key3_orders, price, vat, price_vat FROM [orders] o WHERE group_id = %i")->execute($group_id)->fetchall_skey_assoc();

foreach (
records as $user_id => $user) {
echo
'Jméno :' . $user['name'] . ' ' . $user['sname'];
foreach (
$user['orders'] as $order_id => $data) {
  echo 'Celková cena objednávky s ID ' . $order_id . ' je ' . $data['price_vat'];
}
}

?>

Teď jen co je lepší, jestli tvuj přístup nebo muj, no asi záleži na zvyku, mně asi vyhovuje na první pohled víc to moje ale to je asi tim že zvyk je železná košile a já už bych si na jinej zápis nezvyknul. Spíš by mě zajímalo jak si na tom s rychlostí, já to testoval na 400 000 záznamech (C2D 2,6GHZ ; 4GB RAM, Fedora 7) a měl sem něco přes 7s na podobně složitm dotazu jako je nahoře ale furt optimalizuju tak uvidíme kam se dostanu :)

VK:

Také používám volání fetchAll(PDO::FETCH_ASSOC) hodně často, a to kvůli šablonovacímu systému htmltmpl (mimochodem v Jakubovo dobré úpravě). Čistý PDO statement se dá sice procházek konstrukcí foreach, ale nelze na něj například zavolat funkci count(). A onen šablonovací systém v cyklech automaticky definuje pomocné proměnné nesoucí informace, zda je aktuální průchod lichý a podobně, nicméně využívá k tomu právě volání count($cyklovanaPromenna). Nechám ještě hovořit nějaký kód:

PHP část:

<?php

$page
->setVar('lide',$pdo->query('
  SELECT jmeno,prijmeni
  FROM tabulka
'
)->fetchAll(PDO::FETCH_ASSOC));

?>

htmltmpl část:

<TMPL_IF lide>
<table>
  <TMPL_LOOP lide>
  <tr<TMPL_IF __ODD__> class="odd"</TMPL_IF>><td><TMPL_VAR jmeno></td><td><TMPL_VAR prijmeni></td></tr>
  </TMPL_LOOP>
</table>
</TMPL_IF>

Zde kdybych předal šabloně pouze výsledek $pdo->query(), nefungovalo by správně ono vyznačování lichých řádků.

ikona Techi:

Zend Framework

$db->fetchRow($select); // první sloupec

$db->fetchColumn($select); // první sloupce

$db->fetchPairs($select); // asociativní pole sloupec1 => sloupec2

$db->fetchAll($select); // všechno do asociativního pole

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.