Problém s dotazem při spojování tabulek. Jak funguje JOIN?

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

Zdravím,

potřebuji poradit s chybou v dotazu do DB.

Dotaz v modelu:

SELECT `article_has_file`.`file_id`, `file`.`id`
FROM `article_has_file`
LEFT JOIN `file` ON `article_has_file`.`file_id` = `file`.``
WHERE (`article_has_file`.`article_id` = ?)

Vypíše chybu: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‚file.‘ in ‚on clause‘

Není mi jasné proč se nedoplní file.id v části ON. Jak vlastně funguje sestavení JOIN dotazu?

Díky moc. Pokud to není jasné, rád upřesním.

enumag
Člen | 2118
+
0
-

Jaký PHP kód v tom modelu voláš?

SendiMyrkr
Člen | 30
+
0
-

na koncí tý řádky s ON máš file.``“ takže se snažíš vybrat jakoby z tabulky file sloupec bezejména…

edit.
sorry nedočetl jsem to celý… máš na tom sloupci id primary key?

Editoval SendiMyrkr (22. 10. 2012 1:29)

iskejp
Člen | 41
+
0
-

To Enumg: PHP v modelu je následující.

public function getFileUse ($articleId) {
    return $this->select('article_has_file.file_id, file.id')->where('article_has_file.article_id = ?', $articleId);
    }

To SendiMyrkr: Ano, id je PRIMARY KEY. Ještě pro jistotu dodávám, že mám aktuální verzi Nette 2.0.6.

enumag
Člen | 2118
+
0
-

To vypadá na bug.

Proč tam vůbec máš ‚article_has_file.file_id, file.id‘, když je to totéž?

Dále $this vypadá, že je Selection, dovolím si upozornit, že Selection bys dědit neměl.

iskejp
Člen | 41
+
0
-

Tak to jsem rád, že si to nemyslím sám :o).

Jinak model vypadá takto:

class AddFiles extends Selection {

public function __construct(Connection $connection)
    {
        parent::__construct('article_has_file', $connection);
    }

public function insertFile ($articleId, $fileId, $userId) {
        return $this->insert(array(
           'article_id' => $articleId,
           'article_user_id' => 1,
           'file_id' => $fileId,
           'file_user_id' => $userId
        ));
    }

public function getFileUse ($articleId) {
    return select('article_has_file.file_id, file.id')->where('article_has_file.article_id = ?', $articleId);
    }
}

Pokud tam je něco špatně, rád se dozvím jak na to správně. Vycházel jsem z tutorialu.

A co se týče toho dotazu. Mám za to, že article_has_file.file_id vytáhne ID z N:N tabulky a spojí jej s file.id pro načtení dat o souboru.

Díky za pomoc.

ViPEr*CZ*
Člen | 813
+
0
-

Tvorba modelů byla v quickstartu nově předělaná… mrkněte na to ;-)

iskejp
Člen | 41
+
0
-

Opět zdravím,

bohužel mi stále JOIN nefunguje. Nastudoval jsem změny modelů (jsou hezké), instaloval nejnovější verzi Nette, ale stále nic. Tentokrát mi hází chybu No reference found for $articleFile->articlefile.

Dotaz ve třídě ArticleFileRepository:

public function findFileUse ($articleId)
       {
           return $this->findWhere('articlefile.file_id='.$articleId);
       }

Repository navazující na Quickstart:

public function findWhere($string)
       {
           return $this->getTable()->where($string);
       }

Chybu v laděnce hlásí až render v komponentě při volání count:

public function render(){
            $this->template->setFile(__DIR__.'/FileManage.latte');
           $this->template->file = $this->fileManage;
           $this->template->countFiles = count($this->fileManage);
           $this->template->render();
        }

Díky za pomoc.

enumag
Člen | 2118
+
0
-

$articleFile->file ?

iskejp
Člen | 41
+
0
-

enumag napsal(a):

$articleFile->file ?

Promiň, myslíš v count v komponentě?

enumag
Člen | 2118
+
0
-

Aha, srry, špatně jsem si to přečetl. Chyba je někde tady:

$this->findWhere('articlefile.file_id='.$articleId);

Bez struktury databáze ti neřeknu přesně jak by to mělo být. Možná jen file_id=… bez toho articlefile.

iskejp
Člen | 41
+
0
-

Tak nakonec to nefunguje. Jelikož jsem změnou parametru WHERE zrušil JOIN. Dopracoval jsem se k hlášce:

PDOException #42S22
SQLSTATE[42S22]: Column not found: 1054 Unknown column ‚file.article_id‘ in ‚where clause‘

Dotaz do WHERE:

findWhere('file.article_id='.$articleId)

S tím, že výsledné SQL je:

`SELECT `articleFile`.*
FROM `articleFile`
INNER JOIN `file` ON `articleFile`.`file_id` = `file`.``
WHERE (`file`.`article_id`=13)`

Kde je chyba je mi jasné. V tabulce file žádný sloupec article_id neexituje. Jenže pak nevím jak tedy vytvořit JOIN 2 tabulek. Navíc je podezřelé, že je prázdný řetězec file.``.

Můžete někdo poradit jak to vlastně funguje? Díky.

Editoval iskejp (12. 11. 2012 22:23)

enumag
Člen | 2118
+
0
-

Promiň, ale jsem poněkud zmaten.

  1. Struktura db?
  2. Jaká data z ní chceš vytáhnout?

Možná ti pomůže tohle.

iskejp
Člen | 41
+
0
-

Zdravím,

při pokusu o nalezení řešení problému se spojováním tabulek jsem vytvořil vlákno, které se postupem doby opět vyvinulo ve stejný problém. Myslím, že patří spíše sem.

https://forum.nette.org/…g-conversion#… (Na odkazu je výpis kódu a struktury DB.)

Při pokusech o nalezení řešení jsem přesunul dotaz do DB z ArticleFileRepository do FileRepository a změnil kód dotazu na tento:

return $this->findJoin('13:articlefile:file_id');

Vysvětlivka: 13 je pokusné ID článku ke kterému se mají připojit soubory. Dle mého pozorování má být na tomto místě $key a nikoli $table jak je uvedeno v návodu výše od enumaga.

Laděnka pak hlásí „Array to string conversion“ a toto:

 ...\libs\Nette\Database\Table\SqlBuilder.php:323 source ▼  Nette\Database\Drivers\MySqlDriver-> delimite (arguments ▼)
$name

array(2) ▼ [
   0 => "id" (2)
   1 => "user_id" (7)
]

Pokud se nepletu, je toto spíše funkční a správná cesta, které ovšem někde selhává. Bohužel nemohu vůbec přijít kde. Můžete opět poradit, či naťuknout?

Díky.

enumag
Člen | 2118
+
0
-
  1. Pokud stále používáš Nette 2.0.x, raději si stáhni 2.1-dev. NDB je ve 2.0 poněkud zabugovaná.
  2. Upřesni jak vypadá metoda findJoin a její volání, zde uvádíš implementace se dvěma parametry a v tomto vláknu volání s jedním parametrem což fungovat zcela určitě nemůže.
iskejp
Člen | 41
+
0
-

Zkusil jsem nasadit vývojovou verzi, ale je tam toho asi poměrně dost jiného a nepodařilo se mi to správně odladit :o(.

FindJoin vypadá takto:

public function findJoin($select/*, $where*/)
        {
            return $this->getTable()->select($select)/*->where($where)*/;
        }

Zkoušel jsem jej bez části where, jelikož mi přišlo, že JOIN v Nette funguje buď přes WHERE, nebo přes SELECT, ale nikoli přes oboje.

EDIT: Nakonec jsem to vyřešil přes query.

Editoval iskejp (24. 12. 2012 16:45)