NBD bug? Jednoduchý leftjoin

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

Nette 2.1dev, PHP Version: 5.4.12, MySQL Version: 5.6.16, zkoušeno i na Nette 2.0.10 se stejným výsledkem.

public function renderDefault() {
    $this->template->anyVariable = 'any value';
    $a = $this->selectionFactory->table('table1')->where(':table2.table3_id', '1')->order(':table2.poradi');

    echo 'spatne: ';
    foreach ($a as $b) {
        echo $b->id . ' | ';
    }

    $spravne_query_co_mi_vyhodi_ladenka_z_toho_nahore = $this->database->query('SELECT `table1`.*
                                    FROM `table1`
                                    LEFT JOIN `table2` ON `table1`.`id` = `table2`.`table1_id`
                                    WHERE (`table2`.`table3_id` = 1)
                                    ORDER BY `table2`.`poradi`');
    echo '<br /> dobre: ';
    foreach ($spravne_query_co_mi_vyhodi_ladenka_z_toho_nahore as $c) {
        echo $c->id . ' | ';
    }
}

Výstup:

spatne: 1 | 2 | 3 |
dobre: 1 | 2 | 3 | 1 | 3 | 1 | 2 |

Databáze:

CREATE TABLE IF NOT EXISTS `table1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;


INSERT INTO `table1` (`id`, `name`) VALUES
(1, 'prvni'),
(2, 'druhy'),
(3, 'treti'),
(4, 'ctvrty'),
(5, 'paty');

CREATE TABLE IF NOT EXISTS `table2` (
  `table1_id` int(11) NOT NULL,
  `table3_id` int(11) NOT NULL,
  `poradi` int(11) NOT NULL,
  KEY `fk_table2_table1_idx` (`table1_id`),
  KEY `fk_table2_table31_idx` (`table3_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `table2` (`table1_id`, `table3_id`, `poradi`) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(1, 1, 4),
(3, 1, 5),
(1, 1, 6),
(2, 1, 7);

CREATE TABLE IF NOT EXISTS `table3` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;


INSERT INTO `table3` (`id`, `name`) VALUES
(1, 'asdf');

Už jsem s NDB začínal být spokojený, ale po 4 dnech bez odpovědi to nazvu bugem a jdu se podívat po něčem jiném :/

vvoody
Člen | 910
+
0
-

Napíš sem aj prvé query ktoré ndb vygeneruje, je v debugu bare.

newbie
Člen | 31
+
0
-

No v tom je právě ten problém, dotaz který NBD vygeneruje jsem vzal a zkopíroval do $spravne_query_co_mi_vyhodi_ladenka_z_toho_nahore. Takže ještě jednou. NBD mi vygeneruje tento dotaz (ladence/debuggeru)

'SELECT `table1`.* FROM `table1 LEFT JOIN `table2` ON `table1`.`id` = `table2`.`table1_id` WHERE (`table2`.`table3_id` = 1) ORDER BY `table2`.`poradi`'

Dotaz je vygenerovaný správně jeho výpis přes fluent zápis je špatně

public function renderDefault() {
    $this->template->anyVariable = 'any value';
    $a = $this->selectionFactory->table('table1')->where(':table2.table3_id', '1')->order(':table2.poradi');

    echo 'spatne: ';
    foreach ($a as $b) {
        echo $b->id . ' | ';
    }
	// tady ten dotaz pod tim jsem vzal a zkopiroval z debugru z toho zapisu nahore, uz nevim jak jinak bych to  řekl
    $spravne_query_co_mi_vyhodi_ladenka_z_toho_nahore = $this->database->query('SELECT `table1`.*
                                    FROM `table1`
                                    LEFT JOIN `table2` ON `table1`.`id` = `table2`.`table1_id`
                                    WHERE (`table2`.`table3_id` = 1)
                                    ORDER BY `table2`.`poradi`');
    echo '<br /> dobre: ';
    foreach ($spravne_query_co_mi_vyhodi_ladenka_z_toho_nahore as $c) {
        echo $c->id . ' | ';
    }
}

Výstup:

spatne: 1 | 2 | 3 |
dobre: 1 | 2 | 3 | 1 | 3 | 1 | 2 |

Dělá mi to i v nette 2.0.10 už nevím na jaké konfiguraci, ale stejné chování.

Editoval newbie (10. 8. 2013 20:53)

enumag
Člen | 2118
+
0
-

Problém je v tom že na výstupu má být řádek se stejným ID několikrát. To NDB neumí, v podstatě to funguje jako kdybys přidal DISTINCT.

Řešení je vybírat záznamy ne z tabulky 1, ale z tabulky 2 a pro natažení odpovídajících záznamů z tabulky 1 použít $row->table1->id.

Zda je to chyba nebo ne nevím. Na to asi dokáže odpovědět jen @hrach.

newbie
Člen | 31
+
0
-

No právě tomu načítání z jiné tabulky se chci vyhnout. Jde mi o to že předávám data komponentě a chci ji předávat vždy data podle table1 podle různých jiných parametrů, nebo jiných M:N vztahů. Jde mi o její šablony, abych nemusel mít dvě šablony pro výpis, jenom kvůli tomu že se mi nepodaří vytáhnout data z table1.

šablona 1 – podaří se mi vytáhnout data z table1:

{foreach $table1 as $row}
	{$row->id}

šablona 2 – nepodaří se mi vytáhnout data z table1:

{foreach $table2 as row}
	{$row->talbe1->id}

Tady na tenhle problém jsem u sebe narazil na celkem dost místech(a nikdy nad tím nepřemýšlel) a snažil jsem se to zrefaktorovat, bohužel jsem skončil na takové podle mě základní chybě? vlastnosti? někde mi zas něco uniká?

Editoval newbie (10. 8. 2013 21:38)

vvoody
Člen | 910
+
0
-

Robíš to zle, z databáze prenášaš duplicitné dáta. @enumag ti radí dobre, preto rieš prečo ti to nejde tím spôsobom. Začni napríklad tým ako sa prejavuje:

šablona 2 – nepodaří se mi vytáhnout data z table1:

nedaří znamená čo? nejaká exception?

newbie
Člen | 31
+
0
-

vvoody napsal(a):

Robíš to zle, z databáze prenášaš duplicitné dáta. @enumag ti radí dobre, preto rieš prečo ti to nejde tím spôsobom. Začni napríklad tým ako sa prejavuje:

šablona 2 – nepodaří se mi vytáhnout data z table1:

nedaří znamená čo? nejaká exception?

@enumag výborně popsal můj problém, zkus si prosím jeho odpověď přečíst ještě jednou. Já už vážně nevím jak jinak bych to měl popsat. Žádná exception, prostě nedokážu vypsat data čistě podle table1 tak jak chci. A s tím mám dál problém že tvořím všude dvě šablony buď pro zdrojovou tabulku table1, nebo když to nejde další šablonu pro přístup z venku. Tomu se chci vyhnout

Editoval newbie (10. 8. 2013 22:02)

newbie
Člen | 31
+
0
-

Tak já to zkusím popsat ještě jednou. Můj hlavní problém výborně popsal enumag Problém je v tom že na výstupu má být řádek se stejným ID několikrát. To NDB neumí, v podstatě to funguje jako kdybys přidal DISTINCT. Děkuji. Sám od začátku nevím jak to vzít, popsat a uchopit.

Takže pokud to NDB neumí a ani to z principu nemá umět (?), tak bych potřeboval vyřešit následující: Mám úplně hloupoučkou komponentu, která z venku dostane data a jenom je vypíše:

{foreach $table1 as $row}
	{$row->id}

Tohle funguje pokud jí ty data můžu předat z table1. Pokud jí ty data musím předávat třeba (protože to v NDB nejde) podle jiné tabulky (table2, table3) šablona musí vypadat takhle

{foreach $data_by_table2 as $row}
	{$row->table1->id}

Takže to řeším tak že mám dvě šablony pro dva případy. Ok, takhle mi všude všechno funguje a nemám problém, ale je to nehezké. Když z hloupoučké komponenty udělám reálnou, tak mít dvě třeba 50ti řádkové šablony a v nich jenom měnit $row->id na $row->table1->id je prostě blblost.
Nějaké rozumné řešení?

Editoval newbie (10. 8. 2013 23:20)

enumag
Člen | 2118
+
0
-

@newbie: No ono je to tím, že v druhém případě potřebuješ na výstupu duplicitní data. Jediné řešení co mne teď napadá je vlastní iterátor, kterým by se obalilo to Selection v druhém případě a to ->table1 by se schovalo do něj.

hrach
Člen | 1838
+
0
-

Problém: NDB groupuje dle primarniho klice z „primarni“ tabulky, tzn. te, na ktere zacinas stavet ten selection. To se menit nebude ;)

Vzhledem k imaginarnimu zadani (nejake table1, etc.) nebudu to dale studovat, kdyz nejsou jasne semanticke vazby. Obcas muze byt resenim korektni definice primarniho klice.

newbie
Člen | 31
+
0
-

O co konkrétně šlo. Šlo o výpis skladeb. Dokážu je vypsat podle ostatních tabulek – podle žánrů, podle interpretů, podle alb, nebo jen tak podle abecedy, podle data přidání… kde všude jsou skladby unikátní. Pak jsem se dostal k problému že chci skladby vypsat do stejné komponenty podle playlistu a jeho pořadí pro přehrávání. Tam už může být skladba třeba desetkrát za sebou. Table1 jsou skladby a table2 je v podstatě playlist. Když se grupuje podle pirmarniho klice z primarni tabulky, tak data podle table1 vybrat timhle zpusobem nepujdou a tenhle problém musím řešit jinde (zatim v šablonách kde mám dvě verze podle toho odkud data beru).

hrach
Člen | 1838
+
0
-

Dle popsane logiky to bych opravdu rozdelil. Do playlistu zvlast, tam totiz nefiltrujes playlistem, ale skladby jsou jeho „detmi“.