Neočekávaná chyba: ‚id‘ is ambiguous

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Eda
Backer | 220
+
0
-

Zdarec.

Mějme databázové schéma mnoha tabulek s rozmanitými vazbami mezi nimi obsahující mimo jiné tyto dvě tabulky:

Například v presenteru mějme tento kód.

$item = $this->db->table('table1')
	->where('id', 5)
	->fetch();

Všechno je v pořádku, vyhledáváme podle ID v první tabulce. Může se ale stát, že v našem systému mnoha tabulek budeme chtít začít filtrovat záznamy i podle hodnot z druhé tabulky (což je filozofie Nette\Database, pokud se nepletu :-) ).

$item = $this->db->table('table1')
	->where('id', 5)
	->where('table2:columnFromTable2', 1)
	->fetch();

Všechno na první pohled vypadá ok, skript ale skončí chybou Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous, protože se vygeneroval dotaz:

SELECT `table1`.*
FROM `table1`
INNER JOIN `table2` ON `table1`.`id` = `table2`.`id`
WHERE (`id` = ?) AND (`table2`.`columnFromTable2` = ?)

Prosím tedy o opravu, spočívající v přidání názvu bázové tabulky před vyhledávané parametry, které nemají explicitně uvedenou tabulku jinou.

Jen pro úplnost: verze Nette 2.0.10.

Tomáš Votruba
Moderator | 1114
+
0
-

Ahoj, to už by zřejmě bylo příliš magické. Pokud přidáš druhou tabulku, resp. specifický sloupec z ní, je potřeba odlišit id v té první. (Nepoužívám NDB, ale v NotORM je praxe stejná.)

$item = $this->db->table('table1')
    ->where('table1.id', 5)
    ->where('table2:columnFromTable2', 1)
    ->fetch();

@enumag: fixed, díky.

Editoval Schmutzka (11. 3. 2013 16:57)

enumag
Člen | 2118
+
0
-

@Schmutzka: Má to být table1.id. Jinak už se to tady řešilo, možná se tam ten název primární tabulky časem bude doplňovat automaticky, nebude-li explicitně uvedená jiná tabulka.

Eda
Backer | 220
+
0
-

Schmutka:
Přijde mi naopak magické, nebo spíš trošku nešťastné, že přidáním podmínky z cizí tabulky dotaz spadne kvůli nějaké původní podmínce. V ještě horším případě (vyměním podmínku ->where('user1.name', 'Honza') za ->where('user2.name', 'Honza')) se bude brát úplně jiný sloupec než původně, skript naopak nespadne a dokud si nevšimneme nekonzistence dat v databázi, bude nám takovýto dotaz potajnu dělat například neplechu v uživatelích. Může to způsobovat nečekané chyby, proto by měl být výklad toho, co znamená ->where('id', 5) jednoznačný. Tohle je přesně věc, kterou si myslím, že by měla vrstva Nette\Database od uživatele odstínit.

To opravdu při každém dotazu preventivně před každý sloupec ve where přidáváte název bázové tabulky? Co když dotaz někdy v budoucnu rozšíříte? A nebo, co hůř…, když budete mít nějaký systém, který bude where kritéria nějak dynamicky přidávat? :-)