NotORM používané Nette – dotazy
- Oggy
- Člen | 306
reaguji na přesunutí dotazů ohledně NotORM ..
Oggy:
lze nějak docílit LEFT JOIN nebo ho hezky obejít ?
např. dostat nějaký takovýto dotaz:
<?php
SELECT COUNT(*) FROM todo LEFT JOIN project ON todo.project_id = project.id WHERE (project.archived = 0 OR project_id IS NULL)
?>
NOTORM generuje tento dotaz:
<?php
SELECT COUNT(*) FROM todo INNER JOIN project ON todo.project_id = project.id WHERE (project.archived = 0 OR project_id IS NULL)
?>
při
<?php
{=Todo::fetchAll()->where('project.archived = 0 OR project_id IS NULL')->count("*")}
?>
cíl je dostat počet TODO, které patří k nearchivovaném PROEJKTu a nebo k žádnému projektu..
Jakub Vrána:
V tomto konkrétním dotazu by se to dalo vyřešit použitím project.id místo project_id nebo by se dokonce celá podmínka dala zjednodušit na ‚project.archived <⇒ 0‘. Ale přemýšlím, že bych podporu pro INNER JOIN vyhodil, protože to je jen výkonnostní optimalizace a někdy může být očividně matoucí.
Oggy:
To si nejsem jist zda by šlo ..project.id nemůže být nikdy NULL .. a jakmile zapíši project.neco .. dostavam JOIN v tomto případě INNER, a tím znemožním dostat se k záznamu TODO, který nepatří k žádnému projektu (jeho project_id je NULL) .. Podle mě ten JOIN musí být LEFT ..
nebo ne?
- vrana
- Člen | 131
Vtip je v tom, že když napíšeš project.id IS NULL
, tak to
NotORM pochopí a místo INNER JOIN vyrobí LEFT JOIN. Můžeš si to
vyzkoušet.
Ale nakonec jsem podporu INNER JOIN z NotORM skutečně vyhodil. Byla to totiž pouze výkonnostní optimalizace, která je přinejmenším v MySQL zbytečná. Do Nette se tato změna jistě také časem dostane.
- Oggy
- Člen | 306
vrana napsal(a):
Vtip je v tom, že když napíšeš
project.id IS NULL
, tak to NotORM pochopí a místo INNER JOIN vyrobí LEFT JOIN. Můžeš si to vyzkoušet.Ale nakonec jsem podporu INNER JOIN z NotORM skutečně vyhodil. Byla to totiž pouze výkonnostní optimalizace, která je přinejmenším v MySQL zbytečná. Do Nette se tato změna jistě také časem dostane.
Ano, super .. pořád mě NotORM překvapuje :-)
Jen by bylo fajn do budoucna .. tohle jsou věci, které člověk z dokumentace nevyčte. Naštěstí je možnost se ptát zde, tímto děkuji :-) za tvé odpovědi.
- vrana
- Člen | 131
Už včera jsem zároveň s vyhozením INNER JOIN upřesnil dokumentaci tak, aby bylo jasné, že se vytváří LEFT JOIN.
- bojovyletoun
- Člen | 667
měl bych doataz k vícenásobným referencím → lze je používat třeba
takto
$db->table('view')->select('viewparam.clovek_typ.clovek.jmeno');
?
Mohou být reference v obou směrech ?
Např:
viewparam(clovek_typ_id,view_id) odkazuje na
view(id,jmeno) a na clovek_typ(id, jmeno)
;** clovek(id,jmeno, clovek_typ) odkazuje na **clovek_typ
Není v plánu dát do NotOrm (Nette) něco jako fetchAssoc a fetchAll? Protože na jednoduché dumpnutí celé result sady není funkce.
něco takového
dump(array_map(function($r){return $r->toArray();}, iterator_to_array($data)));
Editoval bojovyletoun (20. 1. 2011 11:00)
- Oggy
- Člen | 306
Mám tu ještě pro mě takový oříšek na zapsání v NotORM syntaxi ..
schema:
project – entry – entry_tag – tag
potřebuji vypsat SUM(time) – který si drží jednotlivé ENTRY ..ale jen u těch entry u kterých TAG končí znakem ‚*‘ … patřící k nějakému PROJECTU ..
člověk je zvyklý napsat dotaz s několika JOINY, ale v syntaxi NotORM si nejsem úplně jist..
moje pokusy:
nejdřív jsem napsal něco takového, ale to není správně.. protože při procházení foreachem ..se generuje další dotaz a už se „netýká“ ENTRY, u kterého je zaznamenán ‚time‘
<?php
foreach (self::$notORM->entry('project_id',$id) as $entry) {
list($time) = $entry->entry_tag()
->where("tag.name regexp '*$'")
->aggregation('SUM(entry.time)');
/*foreach($entry->entry_tag() as $entry_tag) {
list($time) = $entry_tag->tag("regexp '*$'")->aggregation('SUM(time)');
}*/
}
return $time;
?>
- vrana
- Člen | 131
Pokud to jde, tak příklady prosím uvádějte na demo databázi.
V ní se to vyřeší takhle (NotORM syntaxe):
<?php
$applications = $db->application_tag("tag.name LIKE ?", "%*")->select("application_id");
echo $db->application("author_id", $id)->where("id", $applications)->max("title");
?>
Položený dotaz:
SELECT MAX(title) FROM application WHERE (author_id = 1) AND (id IN (
SELECT application_id
FROM application_tag
LEFT JOIN tag ON application_tag.tag_id = tag.id
WHERE (tag.name LIKE ?)
));
- krissott
- Člen | 48
Mám malinký dotázek k NotORM. Zde je schéma db . Mám 2 tabulky: company a address. Company může mít 2 adresy: fakturační a adresu centrály. Obě odkazují na stejnou tabulku address.
Tabulka company má tedy 2 cizí klíče:
- (
address_id
) REFERENCESaddress
(id
) – fakturační adresa - (
head_address_id
) REFERENCESaddress
(id
) – adresa centrály
Když se chci dostat v šabloně k fakturovací adrese vše je
v pořádku.
Pokud ale potřebuji vytáhnout data z adresy centrály, nastane problém.
<?php
{$company->address} // tohle je ok
{$company->head_address} // samozrejme hleda tabulku head_address, ktera neexsituje
?>
Napadá mě, jak to obejít, ale chtěl bych se zeptat na čisté
řešení.
Samozřejmě je možné převést relaci na M:N, ale to bych nechtěl.
Díky
- dakota
- Člen | 148
V NotORM to môžeš vyriešiť cez Structure – http://www.notorm.com/#…
V Nette\Database\Selector sa to zatiaľ nedá.
- bojovyletoun
- Člen | 667
Ano, na tohle jsem s ptal + odpověď
Samozřejmě když jsem psal tu kontigenční tabulku, tak to s Nette\Database prostě nešlo (kvůli čistotě šablon)→ přešel jsem k dibi::fetchAssoc
Na druhou stranu, pak jsem k té aplikaci k některému záznamu
potřeboval přidat nějaké hodnoty, tak jsem zase „viděl“, že
s Nette\Db by to šlo po másle než přes sql- místo 4 joinů ve fluent bych
měl jen něco ve
stylu $db->table(x)->get(13)->related(x)
Ale nakonec jsem zůstal u dibi (asi protože na ostrém servru stejně PDO sqlite nebylo)
- krissott
- Člen | 48
Můžete mi pls někdo poradit, jak se dělají subselecty v NotORM popř. \Nette\Database? Nebo jak by se řešilo něco takového?
<?php
SELECT count(records.region_id) AS occurs FROM (SELECT region_id FROM `record` GROUP BY `id`) AS records GROUP BY(region_id);
?>
Díky…
Editoval krissott (3. 2. 2011 10:00)
- dakota
- Člen | 148
Myslím, že použitie derivovaných tabuliek vo FROM (…) alebo JOIN (…) v NotORM ani Nette\Database\Selector nie je možné – https://forum.nette.org/…-predstaveni#….
Nedostaneš rovnaký výsledok použitím:
SELECT region_id, COUNT(region_id) AS occur FROM record GROUP BY region_id
v Nette\Database\Selector:
$db->table('record')->group('region_id')->select('region_id, COUNT(region_id) AS occur');
Alebo sa mýlim.
Editoval dakota (3. 2. 2011 11:09)
- krissott
- Člen | 48
vrana napsal(a):
Raději napiš, co chceš udělat. Tento dotaz vypadá dost podezřele – při agregaci by se neagregující sloupce měly získávat jen po použití agregační funkce, jinak to v některých databázích ani nejde (a MySQL vezme náhodnou hodnotu).
Sorry, že píšu, tak pozdě. Dostal jsem se k tomu až teď.
Popíšu ti tedy co řeším za problém. NotORM resp. \Nette\Database
používám krátce, ale zatím jsem s ním velmi spokojen, jen ho ještě
neovládám, jak bych chtěl.
Mám db, kde jsou tyto tabulky:
company(address_id…)
address(city_id…)
parameter(id,name…)
company_parameter(company_id,parameter_id)
Jedná se o klasický katalog firem, kde se vyhledává na základě adresy
a parametrů.
Jak bys teda řešil dotaz v NotORM, kdy potřebuješ vypsat jen firmy
z nějakého města, které navíc splňují nějaký parameter. (WHERE
city_id=? AND parameter_id=?).
A navíc je nad výpisem seznam měst u kterých potřebuju vypsat počet
daných firem, dle filtru.
Tady máš výstřižek schéma z db: http://ukaz.at/17t .
Editoval krissott (28. 2. 2011 8:55)
- vrana
- Člen | 131
Firmy z nějakého města, které navíc splňují nějaký parametr:
$db->company_parameter("company.address.city_id", $city_id)->where("parameter_id", $parameter_id)
.
Alternativně by to šlo i přes $db->company()
.
Seznam měst s počtem firem:
$db->company()->group("address.city_id")->select("address.city_id, COUNT(*)")
.
- mino
- Člen | 16
$row = $db->$tableName()->insert($array, ...)
Insert multiple rows by a single INSERT and returns the first row
Ako tam napchat taketo pole?
$array=array(array("key1"=>value,"key2"=>value),array("key1"=>value,"key2"=>value),array("key1"=>value,"key2"=>value),....)
nebolo by lepsie spravit aj
$db->$tableName()->insertMulti($array)
a preslo by si
to samo?
Editoval mino (5. 2. 2011 23:12)
- krissott
- Člen | 48
vrana napsal(a):
Firmy z nějakého města, které navíc splňují nějaký parametr:
$db->company_parameter("company.address.city_id", $city_id)->where("parameter_id", $parameter_id)
. Alternativně by to šlo i přes$db->company()
.Seznam měst s počtem firem:
$db->company()->group("address.city_id")->select("address.city_id, COUNT(*)")
.
Díky.
Jak by se ještě prosím tě vypsal seznam měst s počtem firem dle nějakého parametru?
Šlo by vypsat celkově záznamy(jak firmy tak pobočky) podobným způsobem? Jde to udělat čistě za pomocí NotORM? Asi by to chtělo mít místo 2 tabulek company a filial jednu tabulku record, kde by byl cizí klíč company_id a podle něj by se rozhodovalo, zda se jedná o pobočku či firmu. Spojovat 2 tabulky např. do jednoho datagridu asi není moc ideální.
- krissott
- Člen | 48
vrana napsal(a):
„seznam měst s počtem firem dle nějakého parametru“ už jistě zvládneš sám.
NotORM podporuje UNION, takže by změna schématu neměla být potřeba.
Tak jsem musel přejít z \Nette\Database na NotORM, protože se výsledky
dost liší.
V NotORM mi to hned vše fungovalo. Skvělá prace Jakube. Díky.
Jen jsem narazil ještě na jeden problémek.
Jak vypsat firmy, které splňují více parametru najednou? Tzn. např. myčka
která ma automatické i ruční mytí např.
A jak to vypadá s videjkem na MVC? Rád bych se podíval, jak řešíš Model ty.
- vrana
- Člen | 131
Firmy splňující více parametrů třeba takhle:
<?php
$db->company()
->where("id", $db->company_parameter("parameter_id", $par1)->select("company_id"))
->where("id", $db->company_parameter("parameter_id", $par2)->select("company_id"))
;
?>
Pak by to šlo taky takhle:
<?php
$db->company("id", $db->company_parameter("parameter_id", $params)
->group("company_id", "COUNT(*) = " . count($params))
->select("company_id")
);
?>
Nejsem si jist, co bude efektivnější.
Video mám stále v plánu, ale už jsem jednou slíbil leden, tak další termín nechci slibovat.
Editoval vrana (8. 2. 2011 13:47)
- krissott
- Člen | 48
Vše jede jak má. NotORM se mi opravdu začíná líbit.
Další otázečka:
Join dvou tabulek company a address
<?php
$companies = $db->company();
$companies->select('company.id , address.*');
// tento select join neprovede
$companies->select('company.id , address.id');
//tento ano
?>
Je to záměr, že když chci vybrat všechny sloupce dané tabulky, tak se JOIN neprovede?
- krissott
- Člen | 48
Nevím kde dělám zase chybu, ale stále dostávám tuto výjimku: Invalid
parameter number: number of bound variables does not match number of tokens.
Dělá mi to pouze při spojování výpisu (union)
<?php
$companies = $db->company();
$filials = $db->filial();
$string = '%' . $params['title'] . '%';
$companies->where('title LIKE ?', $string);
$filials->where('name LIKE ?', $string);
$records = $companies->union($filials);
?>
Když se podívám do argumentu $bound_input_params, který se předává, tak tam je opravdu pouze jedna proměnná.
<?php
$bound_input_params = array(0 => "%nazev%");
?>
Když vyzkouším každou tabulku zvlášť, tak to funguje, ale jakmile se je pokusím spojit, tak se vyhodi tato výjimka. Dělám někde chybu, nebo to je bug?
Díky
Editoval krissott (27. 2. 2011 14:39)
- vrana
- Člen | 131
Nejjednodušší bude použít IN:
<?php
$tag_ids = array();
foreach ($tags as $tag) {
$tag_ids[] = $tag["id"];
}
$db->application()->where("tag_id", $tag_ids);
?>
Ale jestli to $tags
není potřeba na nic jiného, tak se dá
napsat rovnou:
<?php
$db->application()->where("tag_id", $db->tags(/* zde podmínka */));
?>
Struktura databáze je předpokládám jiná než v demu, protože tam
v tabulce application
žádné tag_id
není.
- vrana
- Člen | 131
V NotORM to jde pomocí vlastní struktury:
<?php
class NotORM_Structure_Parent extends NotORM_Structure_Convention {
function getReferencedTable($name, $table) {
if ($name == "parent") {
return $table;
}
}
}
?>
Pak už stačí jen
$db->role()->select("role.label as name, parent.label as parent_name")
.
- luco
- Člen | 8
vrana napsal(a):
Firmy z nějakého města, které navíc splňují nějaký parametr:
$db->company_parameter("company.address.city_id", $city_id)->where("parameter_id", $parameter_id)
. Alternativně by to šlo i přes$db->company()
.
Mám podobnú schému databázy ako krissott (pre jednoduchosť by som ju
použil).
Ak by som chcel vypísať všetky aktívne firmy (bez ohľadu, či spĺňajú
nejaký parameter_id) tak by som to urobil takto:
$db->company()->where("is_active", 1)
.
Ak by som chcel pridat parameter_id, tak by sa to samozrejme dalo cez:
$db->company_parameter("company.address.city_id", $city_id)->where("parameter_id", $parameter_id)
,
ale tým pádom musím meniť view. Píšeš, že by to alternatívne išlo cez
$db->company()
, ale nenapadá ma žiadne riešenie. Viem, že
NotORM nepodporuje referencie na odkazujúcu tabulku, takže toto mi
nefunguje:
$db->company()->where("company_parameter.parameter_id", $parameter_id)->where("is_active", 1)
.
Dá sa to nejak riešiť?
Vďaka
- vrana
- Člen | 131
gawan napsal(a):
jakub, parent referencia sa používa často, toto by možno bolo dobré pridať aj do dokumentácie na notorm.com ako príklad, pozeral som, tam to nie je.
Díky za tip, přidal jsem to na http://www.notorm.com/#….
- kralik
- Člen | 230
Ahoj,
prosím mohl by zde uvést někdo jak naplnit selectbox ve formuláři daty
z DB přes tento model NotORM?
je tabulka, která obsahuje cizí klíče např. Auta (id, vyrobce, majitel), Majitel (id, jmeno, prijmeni)
Nedaří se mi načíst do selectboxu „Majitel“ obsah tabulky „Majitel“
Mooc díky
t0m
- luco
- Člen | 8
vrana napsal(a):
luco napsal(a):
Píšeš, že by to alternatívne išlo cez
$db->company()
, ale nenapadá ma žiadne riešenie.<?php $db->company("is_active", 1)->where("id", $db->company_parameter("parameter_id", $parameter_id)->select("company_id") ); ?>
Jakub, mám ešte jeden problém: chcel by som do takéhoto dotazu pridať zloženú podmienku. Select by vyzeral nejak takto:
<?php
SELECT * FROM company
LEFT JOIN company_parameter ON company.id = company_parameter.company_id
WHERE is_active = 1 OR (is_active = 0 AND company_parameter.paramater_id = $parameter_id)
?>
Dalo by sa to nejak cez NotORM riešiť?
- vrana
- Člen | 131
luco napsal(a):
SELECT * FROM company LEFT JOIN company_parameter ON company.id = company_parameter.company_id WHERE is_active = 1 OR (is_active = 0 AND company_parameter.paramater_id = $parameter_id)
To jde zrovna samo:
<?php
$db->company("is_active = 1 OR (is_active = 0 AND company_parameter.paramater_id = ?)", $parameter_id);
?>
- Vyki
- Člen | 388
Narazil jsem na problém při joinování. Mám tabulky:
PERMISSION
id | role_id | privilege_id
PRIVILEGE
id | name | resource_id
Z první tabulky vyberu např. permission.id
a ze druhé pouze
privilege.name
a když nebude ve druhé tabulce odpovídající
záznam potřebuji vrátit v permission.id
hodnotu NULL. Je mi
známo, že to bez problémů umožňuje LEFT JOIN
. Mám ovšem
trochu problém s tím jak s ním NotORM pracuje. Pokud dotaz napíšu
následovně tak funguje, ale vybere jenom řádky, kde se v obou tabulkách
vyskytují hodnoty.
$this->getModel('permission')
->select('permission.id AS pid, privilege.name');
Záměnou levé a pravé tabulky bych toho rád docílil, ale NotORM to samozřejmě pobere trochu jinak. Z následujícího kódu logicky vygeneruje:
$this->getModel('privilege')
->select('permission.id AS pid, privilege.name');
vygeneruje dotaz:
SELECT permission.id AS pid, privilege.name
FROM privilege
LEFT JOIN permission ON privilege.permission_id = permission.id
kde ovšem podmínka nesedí. Má tam být
privilege.id = permission.privilege_id
. Rozumím tomu, že NotORM
nemůže vědět, že potřebuji dotaz položit takto. Ve všech aplikacích mi
spojování tabulek funguje v pohodě, ale tento specifický případ, který
ovšem nemusí být ojedinělý, zvládnout neumí. Nešla by do NotORM doplnit
podmínka, kde by se dotaz položil, zachitila se vyjímka
SQLSTATE[42S22] Column not found: 1054 Unknown column
a pak se
případně položil s opačnou logikou v podmínce ON
?
Edit: V drtivém množství případů do nebude potřeba, vyjímka se nezachytí a bez problémů můžemě zpracovat výsledek. Na výkonnost by to vliv mít nemělo ne?
Editoval Vyki (10. 5. 2011 23:18)
- vrana
- Člen | 131
Nejlepší bys měl použít filozofii NotORM: tedy nejprve získat
permission
a k němu privilege
a na JOIN se
vykašlat.
NotORM nicméně používá LEFT JOIN, takže nechápu, proč by se měly vybrat jen „řádky, kde se v obou tabulkách vyskytují hodnoty“.
Obrácení dotazu nedává smysl, protože k jednomu privilege
může existovat víc permission
.
- kralik
- Člen | 230
Ahoj,
prosím pomozte mi s nadefinováním správné funkce pro \Nette\Database (verze 2.0alpha php5.3.)
zde je schéma DB
Potřeboval bych získat níže uvedenou Query pomocí hezké syntaxe NotORM, ale vůbec se mi nedaří.
<?php
SELECT invoices.*, firms.nazev AS firma FROM invoices, firms WHERE invoices.stav<>30 AND invoices.firm_id=firms.id AND pred_user_id=3 LIMIT 0,10
?>
proměnná pred_user_id = ? a použití ->limit($lmt, $ofs)
V modelu již používám např. tuto funkci:
<?php
public static function firmyvse()
{
$row = self::$connection->table('firms')
->select('id, nazev')
->order('nazev ASC')
->where('stav <>30')
->fetchPairs('id', 'nazev');
return ($row) ? $row : NULL;
}
?>
mooc díky
- basovnik
- Člen | 23
Ahoj, rozhodl jsem se, že vyzkouším NotORM a narazil jsem na problém, jak jednoduše naplnit formulář defaultními hodnotami z databáze.
Řádek:
<?php
$user = $this->getModel('user')->find($id);
?>
mi vrátí NotORM_Row
a já chci jednoduše použít
konstrukci:
<?php
$this['form']->setDefaults(/*zde chci asociativní pole všech hodnot z tabulky*/);
?>
Nevím, ale jak ten objekt jednoduše převést na pole (něco ve stylu
fetchAssoc()
). Provizorní řešení:
<?php
$this['form']->setDefaults(array('name'=>$user['name'], ...));
?>
mi nepřijde jako ideální!
- basovnik
- Člen | 23
Jo a taky nevím, proč musím mít následující pořadí řádků při mazání:
<?php
$user = $this->getModel('user')->find($id);
$this->flashMessage('Uživatel <i>'.$user['name'].' '.$user['surname'].'</i> byl úspěšně smazán.','success');
$this->getModel('user')->delete($user);
?>
Když prohodím poslední 2 řádky, tak $user ztratí data…