Dvojite vztahy mezi tabulkami
- jednou
- Člen | 14
Ahoj,
resim pripad, podobny strukture https://doc.nette.org/…ase/explorer
Konkretne:

V tabulce Author je vazba na Adresu autora/maintainera.
CREATE TABLE `address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT;
CREATE TABLE `author` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`address_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `address_id` (`address_id`),
CONSTRAINT `author_ibfk_1` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`)
) ENGINE=InnoDB DEFAULT;
Kdyz chci zobrazit adresy autora a maintainera, tak mi to spatne vygeneruje vazbu do tabulky Address.
table(book)->select(title, author.address.name, maintanier.address.name)
SELECT `title`,`address`.`name`,`address`.`name`
FROM `book`
LEFT JOIN `author` ON `book`.`author_id` = `author`.`id`
LEFT JOIN `address` ON `maintainer`.`address_id` = `address`.`id`
LEFT JOIN `author` AS `maintainer` ON `book`.`maintainer_id` = `maintainer`.`id`
Ocekaval bych tohle:
SELECT `title`,`author_address`.`name`,`maintainer_address`.`name`
FROM `book`
LEFT JOIN `author` ON `book`.`author_id` = `author`.`id`
LEFT JOIN `author` AS `maintainer` ON `book`.`maintainer_id` = `maintainer`.`id`
LEFT JOIN `address` AS `author_address` ON `author`.`address_id` = `author_address`.`id`
LEFT JOIN `address` AS `maintainer_address` ON `maintainer`.`address_id` = `maintainer_address`.`id`
Je to featura nebo bug? Delam neco spatne?
- jednou
- Člen | 14
Pridal jsem aliasy. Error hlaska stale stejna:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'maintainer.address_id' in 'on clause'
vygenerovane sql:
SELECT `title`,`address`.`name` AS `author_address`,`address`.`name` AS `maintainer_address`
FROM `book`
LEFT JOIN `author` ON `book`.`author_id` = `author`.`id`
LEFT JOIN `address` ON `maintainer`.`address_id` = `address`.`id`
LEFT JOIN `author` AS `maintainer` ON `book`.`maintainer_id` = `maintainer`.`id`
- jednou
- Člen | 14
Ok, pridávám tedy SQL pro tabulku Book:
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`author_id` int(11) NOT NULL,
`maintainer_id` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `author_id` (`author_id`),
KEY `maintainer_id` (`maintainer_id`),
CONSTRAINT `book_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`),
CONSTRAINT `book_ibfk_2` FOREIGN KEY (`maintainer_id`) REFERENCES `author` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Volam to v presenteru takhle:
$res = $this->database->table("book")->select("title,author.address.name AS author_address,maintainer.address.name AS maintainer_address");
$a = $res->fetch();
Editoval jednou (27. 6. 2016 13:54)
- Felix
- Nette Core | 1270
Tak jsem si to pro jistotu zkusil i u sebe a je fakt ze to nejde. Ale nejsem si jisty, ze je to bug. To by musel odpovedet nekdo kdo nette/database zna do hloubky. (@dg, @DavidMatějka, @hrach, ..)
Tohle projde v pohode, ale udela to 5 dotazu.
foreach ($context->table('book') as $book) {
echo $book->author->address->name;
echo $book->maintainer->address->name;
}
- SELECT
id
,author_id
,maintainer_id
FROMbook
- SELECT
id
,address_id
FROMauthor
WHERE (id
IN (1)) - SELECT
id
,name
FROMaddress
WHERE (id
IN (1)) - SELECT
id
,address_id
FROMauthor
WHERE (id
IN (2)) - SELECT
id
,name
FROMaddress
WHERE (id
IN (2))
To je asi nezadouci.
- Unlink
- Člen | 298
S najnovšou nette database sa to dá spraviť takto
$res = $this->database->table("book")
->select("title,author.address.name AS author_address,ma.name AS maintainer_address")
->alias('maintainer.address', 'ma');
$a = $res->fetch();
Výsledné SQL
SELECT `title`, `address`.`name` AS `author_address`, `ma`.`name` AS `maintainer_address`
FROM `book`
LEFT JOIN `author` `author` ON `books`.`author_id` = `author`.`id`
LEFT JOIN `address` ON `author`.`address_id` = `address`.`id`
LEFT JOIN `author` `maintanier` ON `books`.`maintanier_id` = `maintanier`.`id`
LEFT JOIN `address` `ma` ON `maintanier`.`address_id` = `ma`.`id`
V staršej by tvoj kód fungovať mal, akú verziu presne používaš?
Editoval Unlink (27. 6. 2016 14:13)
- norbe
- Backer | 408
Ono to bude fungovat v jakékoli verzi, ale nesmíš tam mít překlep,
aspoň teda předpokládám, nezkoušel jsem :-) maintanier
vs maintainer
Edit: Blbost špatně jsem se podíval na to kde je problém. Podle mne to můžeš obejít tak, že místo druhého address dáš jen addres, tzn.
$this->database->table("book")->select("title,author.address.name AS author_address,maintainer.addres.name AS maintainer_address");
Editoval norbe (27. 6. 2016 15:41)
- jednou
- Člen | 14
@norbe: S pouzitim „addres“ misto „address“ to obejit nejde. Výsledek:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'address.name' in 'field list'
SELECT `title`,`address`.`name` AS `author_address`,`addres`.`name` AS `maintainer_address`
FROM `book`
LEFT JOIN `author` ON `book`.`author_id` = `author`.`id`
LEFT JOIN `address` AS `addres` ON `maintainer`.`address_id` = `addres`.`id`
LEFT JOIN `author` AS `maintainer` ON `book`.`maintainer_id` = `maintainer`.`id`
- blaztar
- Člen | 93
Z dokumentace:
Hlavní myšlenkou je načítání dat pouze z jedné tabulky a tak, aby se
tyto dotazy pokládaly jen jednou.
Což bych převedl na:
function renderBook()
{
$this->template->book = $this->db->table('book')->get(1); // id záznamu
}
title: {$book->title}
author: {$book->author->name}
address: {$book->author->address->name}
maintainer: {$book->ref('author', 'maintainer_id')->name}
maintainer: {$book->ref('author', 'maintainer_id')->address->name}
- blaztar
- Člen | 93
Jen píšu na co je Nette Database stavěná, ale třeba to půjde.
Nebo použít query:
$this->db->query("
SELECT title, address.name AS author_address, ma.name AS maintainer_address
FROM book
LEFT JOIN author author ON book.author_id = author.id
LEFT JOIN address ON author.address_id = address.id
LEFT JOIN author maintainer ON book.maintainer_id = maintainer.id
LEFT JOIN address ma ON maintainer.address_id = ma.id
")->fetchAll();
Editoval blaztar (27. 6. 2016 19:14)
- CZechBoY
- Člen | 3608
@jednou No buď si forkneš Nette/Database a doděláš si tam podporu nebo použiješ 2.4 RC nebo můžeš použít https://github.com/…rts/database