Spojování tabulek v NotORM

V NotORM se poměrně krkolomně provádí operace, které jdou přes více tabulek. Obvykle jsou sice možné, ale dá to trochu práce a nezvyklého přemýšlení. Vezměme si třeba, že bychom chtěli vypsat všechny aplikace setříděné podle jména autora. Já bych to udělal takhle:

<?php
foreach ($db->author()->order("name") as $author) {
    foreach ($author->application() as $application) {
        echo "$author[name]: $application[title]\n";
    }
}
?>

Položené dotazy (se zapnutou cache):

SELECT id, name FROM author ORDER BY name;
SELECT id, author_id, title FROM application WHERE (application.author_id IN ('12', '11'));

Pokud bychom ale do dotazu chtěli přidat nějakou podmínku z tabulky application, tak se dotaz dost zkomplikuje (pokud zbytečně nechceme procházet i autory vyřazených aplikací).

<?php
$authors = $db->application("slogan LIKE ?", "Database%")->select("author_id");
foreach ($db->author("id", $authors)->order("name") as $author) {
    foreach ($author->application("slogan LIKE ?", "Database%") as $application) {
        echo "$author[name]: $application[title]\n";
    }
}
?>

Položené dotazy:

-- v MySQL
SELECT author_id FROM application WHERE (slogan LIKE ?);
SELECT id, name FROM author WHERE (id IN ('11', '12')) ORDER BY name;
SELECT id, author_id, title FROM application WHERE (application.author_id IN ('12', '11')) AND (slogan LIKE ?);

-- v jiných databázích
SELECT id, name FROM author WHERE (id IN (SELECT author_id FROM application WHERE (slogan LIKE ?))) ORDER BY name;
SELECT id, author_id, title FROM application WHERE (application.author_id IN ('12', '11')) AND (slogan LIKE ?);

Omezit počet vrácených záznamů by tímto způsobem nešlo už vůbec.

Pro tyto úlohy se prostě nejlíp hodí spojování tabulek. Ladislav Ševcůj mi poslal patch, který tuto možnost doplňuje, já jsem ale NotORM napsal proto, abych už nikdy žádný JOIN napsat nemusel, i když bych k tomu měl příjemnější API.

Zamyslel jsem se proto nad tím, jaké API bych si pro řešení této úlohy představoval, a dospěl jsem k tomuto:

<?php
foreach ($db->application("slogan LIKE ?", "Database%")->order("author.name") as $application) {
    echo $application->author["name"] . ": $application[title]\n";
}
?>

A to je vše, pohodlnější to být už nemůže. Cizí tabulky se rozpoznávají kdekoliv v dotazu. Položené dotazy:

SELECT application.id, application.author_id, application.title FROM application LEFT JOIN author ON application.author_id = author.id WHERE (slogan LIKE ?) ORDER BY author.name;
SELECT id, name FROM author WHERE (author.id IN ('12', '11'));

Pokud by nám nevadilo, že se jméno autora bude přenášet opakovaně (to v tomto případě asi skutečně nevadí), tak můžeme jeden dotaz ušetřit:

<?php
foreach ($db->application("slogan LIKE ?", "Database%")->select("author.name, application.title")->order("author.name") as $application) {
    echo "$application[name]: $application[title]\n";
}
?>

Položený dotaz:

SELECT author.name, application.title
FROM application
LEFT JOIN author ON application.author_id = author.id
WHERE (slogan LIKE ?)
ORDER BY author.name;
Jakub Vrána, Seznámení s oblastí, 8.11.2010, on-line

Diskuse

ikona Pekelník:

Mohl bys, prosím, doplnit SQL dotaz(y), které tohle provede?
8.11.2010 13:06:45

ikona Jakub Vrána:

Dobrý nápad, doplnil jsem to.
8.11.2010 15:33:33

Franta:

Ten první výpis SQL (dva dotazy) patří k tomu prvnímu výpisu PHP? Nějak to nechápu – vidím tam dva cykly, kolik prvků má $author? Dva? Jak může program při prvním průchodu vnějším cyklem vědět, že budou ještě další autoři a že se má nakonec v SQL objevit IN ('12', '11')? Přijde mi, že v tom článku něco chybí. Co tedy znamená „zapnout cache“?
9.11.2010 21:14:18

ikona Jakub Vrána:

Přečti si nejprve http://php.vrana.cz/notorm.php. Pak ti snad všechno bude jasné.
10.11.2010 11:30:33

Franta:

Tak nějak jsem to čekal – při prvním průchodu cyklem se získají data ke všem dalším prvkům (pro další průchody cyklem). Tenhle styl mi zrovna nesedne (zavolání metody, resp. zjištění vlastnosti, jednoho objektu způsobí načtení dat úplně jiných objektů). Ale už nebudu rýpat, nepoužívám to, ptal jsem se jen tak ze zvědavosti :-)
10.11.2010 13:19:55

ikona Jakub Vrána:

Tento styl se využije v naprosté většině případů, u webových aplikací prakticky vždy – když chci zjistit detail jednoho objektu v cyklu, budu nejspíš chtít zjistit i detail všech ostatních. Pokud bych to ve výjimečném případě nepotřeboval (třeba bych chtěl seznam všech aplikací, ale jen u první bych chtěl jejího autora), dá se to celkem snadno obejít:

<?php
foreach ($db->application() as $application) {
    if ($first) {
        $author = $db->author[$application["author_id"]];
    }
}
?>

Ale ten případ, kdy budu potřebovat všechno, je o tolik běžnější, že pohodlnější syntaxe patří jednoznačně jemu.
10.11.2010 13:33:49

Miroslav Hruška:

Mohu se zeptat, zda lze NotORM využít při spojení dvou databází? Díky.
15.11.2010 17:54:04

ikona Jakub Vrána:

Asi by to nějak šlo, ale s takovou možností nepočítám. Na co by to mělo být potřeba?
15.11.2010 17:55:18

Miroslav Hruška:

Potřebuji spravovat 3 projekty s jedním administračním rozhraním a pro rozdělení výkonu bych to rád postavil na různých databázích.
15.11.2010 18:07:38

Miroslav Hruška:

Tak nakonec to asi vyřeším replikací, ale mám ještě jeden dotaz. Lze nějak pracovat s prefixy tabulek? Díky.
15.11.2010 21:39:32

ikona Jakub Vrána:

Já prefixy tabulek nesnáším, ale mělo by to jít dvěma způsoby:

1. Definicí vlastní struktury (třída implementující NotORM_Structure) – to považuji za vhodný způsob. http://www.notorm.com/#api

2. Psaním kódu v podobě $notORM->{$prefix . "tab"}().
16.11.2010 11:24:06

Tharos:

Jakube, je možné nějak rozumně pracovat s více než dvěmi tabulkami? Mám následující strukturu:

• user
id
username

• companies
id
users_id

• projects
id
companies_id

• log
id
projects_id
date

A potřebuji následující: vypsat všechny položky z tabulky log, které patří k určitému uživateli (restrikce podle users.username) a které jsou dále limitovány určitým datem (log.date) - podle něj také mají být seřazené. Opravdu jsem nenašel hezký způsob, jak tohle v NotORMu napsat. Předem díky za pomoc.
27.12.2010 16:37:51

ikona Jakub Vrána:

Jde to takhle:

<?php
$users
= $db->user("username", $username);
$companies = $db->companies("users_id", $users);
$projects = $db->projects("companies_id", $companies);
$db->log("projects_id", $projects)->where("date", $date)->order("date");
?>

Mám připravený patch, který dovolí psát log.projects.companies.users.username, ale nejsem si jist, že ho zveřejním – jde o poměrně neobvyklý zápis.
27.12.2010 16:55:35

Tharos:

Funguje to výborně, děkuji vřele za reakci. Co se patche týče, minimálně já bych měl o jeho zveřejnění zájem. Osobně se totiž se strukturou databáze, kde se pro některá data zkrátka musí přes více než jednu spojovací tabulku, setkávám ani ne až tak vzácně... A pak už je přece jen NotORM zápis poměrně složitý a dlouhý.
27.12.2010 22:41:22

ikona Jakub Vrána:

Je to v Gitu: https://github.com/vrana/notorm/. Teď by tedy mělo stačit napsat <?php $db->log("projects.companies.users.username", $username); ?>.
29.12.2010 13:23:04

Tharos:

Díky za uveřejnění patche, dnes jsem se konečně dostal k jeho otestování a funguje dobře. Nekoukal jsi ještě na nekorektně vygenerovaný obsah klauzuje IN, o kterém píši v komentáří vedle?
3.1.2011 13:59:42

Tharos:

Tak, malý zádrhel. Řekněme, že v šabloně při vypisování budeme nakonec chtít i nějaké další sloupce například z tabulky companies (řekněme jméno společnosti, ke kterému se záznam v logu vztahuje). Když upravím kód na následující podobu, vygenerovaný dotaz získávající projekty je nesmyslný (je nesmyslná část v IN(...)):

<?php
$users
= $db->user("username", $username);
$companies = $db->companies("users_id", $users)->select('*');
$projects = $db->projects("companies_id", $companies);
$db->log("projects_id", $projects)->where("date", $date)->order("date");
?>
28.12.2010 08:52:52

ikona Jakub Vrána:

K těm stačí přistoupit normálně: $log->projects->companies[""].
28.12.2010 10:03:35

Miroslav Hruška:

Nešlo by do NotROM doplnit něco takového?
<?php
foreach ($notORM->application as $application) {
  echo $application['author.name'] . ' ' . $application['author.web'];
}
?>

Zatím jsem si to upravil sám ve vlastní \NotORM_Row ale něco takového by bylo přínosné myslím pro všechny. Jde o to, že NotORM nepracuje s plošnými daty (jak je většina rozšíření například v Nette zvyklá [DataGrid]). Ve třídě \NotORM_Row stačí upravit metodu offsetGet:
<?php
function offsetGet($key)
{
  if (strstr($key, '.') !== FALSE) {
    $exp = array_filter(explode('.', $key));
    if (count($exp) != 2) {
      return parent::offsetGet($key);
    }
    else {
      $row = $this->__get($exp[0]);
      return $row[$exp[1]];
    }
  }
  else {
    return parent::offsetGet($key);
  }
}
?>

Dalo by se to asi upravit i lépe (další zanoření), například:
<?php
foreach ($notORM->application as $application) {
  echo $application['author.name'] . ' ' . $application['author.company.web'] . ' ' . $application['author.company.region.capital'];
}
?>

Díky za odpověď.
30.1.2011 23:56:55

Miroslav Hruška:

Beru zpět, v NotORM to již takto funguje, předchozí nefunkčnost způsobil špatné pojmenovaný vazební sloupec.
31.1.2011 01:14:50

ikona Jakub Vrána:

Co je špatného na syntaxi $application->author['name']?
31.1.2011 11:06:25

Miroslav Hruška:

Nic, já s tím mám problém pouze v mém datagridu, který přijímá data jako pole a následně generuje tabulku například podle jednoduchého zápisu:
<?php
$table
->data = $notORM->user;
$table->addColumn('name', 'Jméno');
$table->addColumn('sname', 'Příjmení');
$table->addColumn('company.name', 'Firma');
?>

Jinak bych musel psát něco takového:
<?php
  $table
->data = $notORM->user;
  $table->addColumn('name', 'Jméno');
  $table->addColumn('sname', 'Příjmení');
  $table->addColumn('companyName', 'Firma', function($row) {
    return $row->company['name'];
  });
?>
31.1.2011 12:17:26

ikona Jakub Vrána:

Já jsem přemýšlel o tom, že by syntaxe $row['company.name'] přistupovala k datům pomocí JOINu, ale bez zapnuté keše by to bylo strašně pomalé.
31.1.2011 12:19:27

Miroslav Hruška:

Mno to by bylo naprosto super. Možná je to trochu moc magické a nevím, do jaké míry realizovatelné, ale nešlo by tam jen přidat něco jako:
<?php
 
...

  if ($this->cache instanceof NotORM_Cache) {
    //join
  }
  else {
    //2 selecty
  }

  ...
?>

Je to jen nástřel ale myslím si, že rozdílné chování (pokud bude naprosto transparentní) při zapnuté / vypnuté cache by nevadilo, pokud se to napíše do dokumentace. Dalo by se jít ještě dál a založit něco jako "procesor", což by nebylo nic jiného než třída s jednoduchým interface, která by se zaváděla na základě nějakých enviromentálních stavů (cache ano/ne, driver, etc...).
31.1.2011 12:47:50

ikona Jakub Vrána:

Problém je v tom, že pomocí PDO se nedá univerzálně napsat company.name AS `company.name` (neexistuje funkce pro ošetřování identifikátorů). Do NotORM tuto vrstvu dávat nechci, ale v Nette je, takže tam by to přidat šlo.
31.1.2011 21:36:58

ikona Schmutzka:

Pokud s notorm začínáte, nebo potřebujete vědět, jak co napsat (OR, IN s více poli, JOIN, COUNT("*")), vytvořil jsem přehlednou tabulku příkazů, tedy helpku, jak to psát: http://bit.ly/SQLcQ

Snad vám bude nápomocna a ušetří spousty hodin a nervů :)
25.10.2011 11:51:55

Roman Svoboda:

Ahoj,
potřeboval bych pomocí NotORM napsat dotaz:
SELECT c.* FROM content c JOIN content ci ON (c.id = ci.content_id AND ci.template_item_id = $promena)
ORDER BY ci.value DESC, ale netuším, jak na to. :(

Zkoušel jsem :
$this->db->content()->order('content_item.value DESC')->where('content_item.template_item_id = ?',$promenna);

NotORM mi však vygeneruje:
SELECT content.* FROM content
LEFT JOIN content_item ON content.content_item_id = content_item.id
WHERE (content_item.template_item_id = ?)
ORDER BY content_item.value DESC

Nešlo by to udělat nějak jinak prosím?

Předem děkuji za odpověď.
15.3.2012 18:42:28

Roman Svoboda:

Pardon, právě jsem objevil  https://github.com/vrana/notorm/pull/32/files ,
který vyřešil můj problém :)
Pokud však existuje i jiný způsob v NotOrm, jak si to zapsat, určitě by mne zajímal.
15.3.2012 19:40:08

ikona Jakub Vrána:

Já bych to napsal takhle:

<?php
foreach ($db->content_item("template_item_id", $promenna)->order("value DESC") as $content_item) {
    $content = $content_item->content;
}
?>

22.3.2012 05:45:28

Martin Kopeček:

Zdravím, koukám, že už je to tu trošku starší, ale zkusím to:

mám podobný problém s hledáním rozdílu více "stejných" tabulek (šlo by to i v jedné s dalším sloupcem definujícím kategorii:

zpevniky_akordy > zpevniky_id, akordy_id
zpevniky_akordy_koncept > zpevniky_id, akordy_id

a potřeboval bych najít co je v konceptu navíc a co na míň.

např: to, co je navíc:

SELECT zpevniky_akordy_koncept.akordy_id FROM zpevniky_akordy_koncept LEFT JOIN zpevniky_akordy USING(zpevniky_id,akordy_id) WHERE zpevniky_akordy.akordy_id IS NULL

Jde to výše popsaným způsobem, ale přijde mi zbytečné tahat z DB stovky ID, abych je vložil do další query, když je možné vytáhnout jen ty tři podstatné.

Mimochodem, proč je pro mysql vypnuté IN (SELECT...) ? Tím by se to snad dalo také vyřešit.
24.4.2012 15:59:19

ikona Jakub Vrána:

Šlo by to udělat poddotazem. Ten je v MySQL vypnutý, protože ho MySQL vyhodnocuje při každém čtení řádky (postupuje zvenku dovnitř).
21.12.2013 16:07:12

Behe:

Ahoj, předem bych rád poděkoval za NotOrm, ale mám trošku problém s hledáním v několika na sobě závislých tabulkách:

team:
- id
- number
- name

costcenter
- id
- number

team_costcenter
- id
- team_id
- costcenter_segment_id

team_costcenter
- id
- team_id
- costcenter_segment_id

costcenter_segment
- id
- name
- segment_id
- costcenter_id

<?php
foreach ($db->team_costcenter()
            ->where("team.name LIKE '%" . $search . "%' OR
                     team.number LIKE '%"
. $search . "%' OR
                     costcenter_segment.name LIKE '%"
. $search . "%'")
as
$q)
{
    $this->query[] = array('id' => $q->team['id'],
                           'number' => $q->team['number'],
                           'name' => $q->team['name'],
                           'costcenter' => $q->costcenter_segment->costcenter['number'] . ' - ' . $q->costcenter_segment['name']);
}
?>

toto funguje bezproblémů, ale chtěl bych hledat i podle čísla nákl. střediska - tedy přidat do where('costcenter.number LIKE '%" . $search . "%') a to už nefunguje

jde to vůbec tímto způsobem?

Za případnou odpověď předem velice děkuji
3.4.2012 11:23:00

Behe:

jej, tabulka team_costcenter je tam samozřejmě jen jednou.
3.4.2012 11:24:28

Lukas:

Ahoj,

jenom bych chtěl poděkovat za NotORM (a vlastně i za Nette\Database). Ne že by mi to šetřilo práci, ale už nějakou dobu si tvořím vlastní framework (rád si napíšu vlastní než abych se učil cizí) a nad implementováním databází si lámu delší dobu hlavu, hlavně nad automatickým tvořením JOINů (tyhle bastardy píšu fakt nerad). Dost šmejdím po různých frameworcích a hotových řešeních, abych chytl inspiraci (takže se je stejně učím :-/ ). Jenže až díky NotORMu mě cosi "trklo" a já se konečně dopracoval k tomuto (což si myslím vypadá pěkně):

Schéma: http://imageshack.us/photo/my-images/840/dbschema.png/

Jako příklad bude třeba vybrat články seřazené podle nejnovějších komentářů a vybrat k nim i čas a jméno autora posledního komentáře:

<?php
$sql
= $db->table('articles')
    /* addReference přiřadí jakýsi alias cizím klíčům - comments.author_id => users.id */
    ->addReference('author', 'user')
    ->select(
        'id',    // automaticky se přepíše na articles.id
        'title',
        'author.name AS article_author',
        'MAX(comments.posted) AS last_comment_time',    // Agregační (i jiné) funkce lze použít
        'comments.author.name AS last_comment_author')
    ->order('last_comment_time DESC');¨

echo $sql->getSql();
?>
Vypíše
<?php
'
SELECT
    articles.id,
    articles.title,
    author.name AS article_author,
    MAX(comments.posted) AS last_comment_time,
    comments_author.name AS last_comment_author
FROM
    articles
LEFT JOIN
    users AS author ON
    articles.author_id = author.id
LEFT JOIN
    comments AS comments ON
    comments.article_id = articles.id
LEFT JOIN
    users AS comments_author ON
    comments.author_id = comments_author.id
GROUP BY
    articles.id
ORDER BY
    last_comment_time DESC
'
?>
Dobrý, ne?
Finta je v jednotném a množném čísle, díky tomu moje třída ví, zda má hledat author_id v tabulce comments nebo comment_id v tabulce users.

Pokud člověk není vyloženě prase a dodržuje nějakou (jednoduchou) konvenci při návrhu databáze, nepotřebuje ani reflection.

Chtěl jsem se zeptat na dvě věci:
Líbí?
Dokáže NotORM obdobně jednoduchým zápisem vygenerovat takovýto mnohanásobný JOIN?

A ještě se přiznám, že jsem použil toto http://www.kavoir.com/2011/04/php-class-converting-…-english.html pro konverzi z množného čísla na jednotné a opačně (nejsem typ člověka co se spokojí s přidáním "s" na konec, tabulku "propertys" bych nezkousl).

Ještě jednou moc díky Jakube za velkou inspiraci :)

(BTW toto není reklama na nic, svůj FW nejspíš nikdy nikde zveřejňovat nebudu, chtěl jsem jen ukázat, že NotORM pomáhá nejen svým uživatelům, ale dokonce i těm, kteří se snaží udělat si "něco jako NotORM sobě na míru" :D )
11.6.2012 21:58:15

ikona Jakub Vrána:

NotORM klade jednoduché a rychlé dotazy. Tento dotaz nikdy rychlý nebude, protože MAX(comments.posted) se musí při každém dotazu vypočítat znovu, nejde nad ním postavit index. Takže s větším počtem článků bude toto řešení nesnesitelně pomalé.

Když bych to řešil já, tak bych schéma denormalizoval a pomocí triggeru řešil aktualizaci přidaných sloupců. Takže řešení by pak vypadalo takhle:

<?php
foreach ($db->article()->order("last_comment_time DESC") as $article) {
    $comment_author = $article->last_comment->author['name'];
}
?>

18.6.2012 21:46:51

Lukas:

Díky za reakci, je vidět, že se mám ještě hodně co učit. Jediné štěstí, že jsem nikdy na MySQL nestavěl větší databáze. Skutečnost je taková, že osobně triggery (a obecně jakékoliv formy uložené procedury) příliš nemusím kvůli údržbě, člověk na ně musí myslet, nebo si aspoň pustit select * from information_schema.triggers aby věděl, co jaký trigger dělá nebo že tam vůbec nějaký trigger je. Zkušenější to asi sám vyčte už ze struktury, zeptá se "kdepak se mi tady bere ten last_comment_time?", ale u složitějších databází to jasné být nemusí a když má těch triggerů víc, musí pátrat. Máš na to nějakou bezva fintu nebo prostě píšeš komentáře?

Ukazuješ mi naprosto luxusní zápis
<?php $comment_author = $article->last_comment->author['name']; ?>
který je předpokládám ekvivalentní s mým ještě oblíbenějším
<?php $comment_author = $article->last_comment->author->name; ?>
jenže já se musím zeptat: jak NotORM pozná, do jaké tabulky má sáhnout, když se dotážu na $article->last_comment->author[] (tabulka authors neexistuje, chci tabulku users) ? Můžeme totiž například u každého článku chtít třeba i ID moderátora, který povolil zveřejnění neregistrovaným a opět se dotazujeme na tabulku users, je třeba ty názvy odlišit. Nebo dokonce odkazuji na stejnou tabulku (častý příklad: komentáře a reakce) Přiznám se, že mě docela zaskočilo, že to v článku není, protože tento problém se objevuje často a rozhodně si na to nechci psát reflection class, když to můžu vyřešit naprosto jednoduše
<?php $db->addReference('author', 'user')
    ->addReference('reply_to', 'comment'); ?>
případně jsem ještě přemýšlel o možnosti omezení na jednotlivé tabulky
<?php $db->addReference('articles.author', 'user')
    ->addReference('comments.author', 'user')
    ->addReference('comments.reply_to', 'comment'); ?>
Samozřejmě pracuji na MyISAM a cizí klíče neznám. Příklad cos mi ukázal, vypadá příliš "magicky" a nevyčtu z něj, jak NotORM pozná, že author je uložený v tabulce users. Myslím, že by to vyžadovalo jazykově vzdělanou neuronovou síť :-)

A ještě jednou díky za inspiraci a za reakci.
19.6.2012 12:26:55

ikona Jakub Vrána:

Já pro správu databáze používám Adminer, kde triggery vidím u každé tabulky a taky je hned můžu upravit.

Někdo pro dopočítávané sloupce používá nějaký prefix, např. 'computed_'.

NotORM si může strukturu vyčuchat z cizích klíčů pomocí NotORM_Structure_Discovery. To jde samozřejmě jen u InnoDB. Jinak jde strukturu popsat podle vlastní konvence. Viz http://www.notorm.com/#structure.

Z MyISAM doporučuji přejít na InnoDB, zlepší se konzistence dat, sníží riziko jejich ztráty a při víceuživatelském přístupu (běžném u webových aplikací) se kupodivu může i zlepšit výkon.

Ještě ke sloupci reply_to_id – doporučuji přečtení http://php.vrana.cz/traverzovani-kolem-stromu-prakticky.php.
19.6.2012 19:55:15

Lukas:

Dobrá tedy, pochopil jsem, že InnoDB řeší většinu věcí :-) Nicméně (můžu-li trošku OT) jak bys řešil například chat? Všichni píšou jak diví (InnoDB má pomalé inserty, pokud jsem tedy skutečně totálně nezaspal dobu - jakože zatím vidím že spíš jo), k tomu potřebuji cizí klíč author_id => users.id (nemůžu user_id, protože chci ještě třeba last_moderated_by_id => users.id) a i reply_to_id se hodí, když chci mít "namakaný" chat s reakcemi. Bojím se, že traverzování zde vůbec nepomůže, spíš naopak. Nicméně předělání komentářů pod články určitě zvážím, vypadá to vcelku užitečně.

<?php
$db
->addReference('author', 'user')
    ->addReference('reply_to', 'comment');
?>
vs
<?php
class UserStructure extends NotORM_Structure_Convention {
    function getReferencedTable($name, $table) {
        $keys = array(
            'author' => 'user',
            'reply_to' => 'comment'
        );

        if(isset($keys[$name])) {
            return $keys[$name];
        }

        return parent::getReferencedTable($name, $table);
    }
}
?>
Asi chápeš co se tím snažím říct. Jde-li nám prakticky jen o doplnění cizích klíčů do MyISAM (99% případů, řekl bych), hodí se nějaký jednodušší zápis. Proto taky NotORM vznikl - aby nám usnadnil práci s db, nemám pravdu? :-)

Znovu dík, lidi by ti měli za tvé reakce (a články) platit, protože jsou poučnější než 4 roky na střední obor IT!
20.6.2012 04:33:26

ikona Jakub Vrána:

Ony ty inserty zase tak pomalé nejsou. Navíc i u chatu je mnohem častější čtení.

reply_to_id bych opravdu nedoporučoval, mimo jiné proto, že s ním nejde rozumně udělat stránkování. Spíš bych zvolil thread_id a lft+rgt z traverzování.

V NotORM jsem zvolil tohle řešení, protože je univerzální, dovoluje popsat prakticky jakoukoliv strukturu. Nicméně nic nebrání postavit nad tím nějakou další abstrakci, která bude omezenější, ale bude se snadněji používat.

Můj PayPal je např. na https://sourceforge.net/donate/?group_id=264133 :-). Jednu dobu byl i pod každým článkem, ale nikdo to nepoužíval…
20.6.2012 20:24:25

Lukáš:

Super, asi už mě nenapadá žádná otázka, ty máš prostě řešení vždy na všechno :-) Dík za tvůj čas, já si jdu nastudovat InnoDB a pak si napíšu nějakou třídu na traverzování, vypadá to, že to budu potřebovat často, tak ať se to naučím.

PP nemám, ale nějaký drobný ti pošlu třeba přes nějakýho kámoše ;-) Adminer je k nezaplacení.
21.6.2012 00:25:34

Petr:

Zdravím,
mám pár dotazů ohledně spojování tabulek:
mějme tabulky :
kategorie
-id
-název

kategorie_sekce
-kategorie_id
-sekce_id

sekce
-id
název

sekce_produkt
-sekce_id
-produkt_id

produkt
-id
-název

1. jak zjistím název kategorie, název sekce ainformace o produktu,  pokud znám id produktu ?

2. jak vypíšu, postupně kategorie, sekce a produkty
viz podobně jako v demo databázi, ale s třema tabulkama:
foreach ($software->application() as $application) {
    echo "$application[title]\n";
    foreach ($application->application_tag() as $application_tag) {
        echo "\t" . $application_tag->tag["name"] . "\n";
    }
}

3. pokoušel jsem se vytvořit join následovně:
$result = $dotaz->db->q_category()->where("q_category.id",1)
->join("q_category", "LEFT JOIN q_catSub ON q_category.id = q_catSub.q_category_id")
->join("q_catSub", "LEFT JOIN q_subCategory ON q_catSub.q_subCategory_id = q_subCategory.id")
->join("q_subCategory", "LEFT JOIN q_subProd ON q_subCategory.id = q_subProd.q_subCategory_id")
->join("q_products", "LEFT JOIN q_products ON q_subProd.q_products_id = q_products.id")
->select("q_category.*");

což vytvořilo dotaz:
SELECT q_category.* FROM q_category LEFT JOIN q_catSub ON q_category.id = q_catSub.category_id
* LEFT JOIN q_subCategory ON q_catSub.subCategory_id = q_subCategory.id
* LEFT JOIN q_subProd ON q_subCategory.id = q_subProd.subCategory_id
* LEFT JOIN q_products ON q_subProd.products_id = q_products.id
* WHERE (q_category.id = 1)

pokud jsem dal do selektu i výpis jiné tabulky, dotaz se zpřeházel... (chtěl jsem do selektu i výpis q_products.*)

Budu moc rád, za jakoukoli pomoc, "nakopnutí" správnou cestou.

Dkuji
17.5.2013 20:45:22

ikona Jakub Vrána:

Struktura je dost podivná. Produkt může být ve více sekcích, dejme tomu. Ale sekce může být ve více kategoriích? To nedává smysl. Nicméně s touto strukturou databáze by kód vypadal takhle:

<?php
$produkt
= $notORM->produkt[$id];
foreach (
$produkt->sekce_produkt() as $sekce_produkt) {
   
$sekce = $sekce_produkt->sekce;
    foreach (
$sekce->kategorie_sekce() as $kategorie_sekce) {
       
$kategorie = $kategorie_sekce->kategorie;
    }
}
?>

Join vůbec není potřeba.
26.6.2013 21:01:48
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.