3.3. JOIN, pohledy a počítané sloupce
Dotaz může spojovat, počítat i vnořovat – pro grid je výsledek pořád jen sada pojmenovaných sloupců.
Ukázka
Jméno zákazníka z druhé tabulky, počet položek ze třetí. Filtrovat i řadit jde podle obojího.
Zdrojový kód
<?php
declare(strict_types=1);
namespace App\Components\Docs\Data\SqlJoinGridControl;
use App\Enum\OrderStatus;
use Xart\Grid\Button\ButtonManager;
use Xart\Grid\Column\ColumnManager;
use Xart\Grid\Control\GridControl;
use Xart\Grid\DataOutput\Row;
use Xart\Grid\DataSource\DataSource;
use Xart\Grid\DataSource\SQL\SQLDataSource;
/**
* Dokumentace, kapitola 3.3 – JOIN, pohledy a počítané sloupce.
*
* Objednávky se jménem zákazníka z druhé tabulky a s počtem položek z třetí. Filtrovat i řadit jde
* podle obojího: grid si za alias dosadí výraz z dotazu, ne alias samotný.
*/
class SqlJoinGridControl extends GridControl
{
public function createDataSource(): DataSource
{
return new SQLDataSource(__DIR__ . '/SqlJoinGridControl.sql');
}
public function columns(ColumnManager $cm): void
{
$cm->add('number', 'Číslo');
// Sloupec z JOINované tabulky – filtr se poskládá nad výrazem CONCAT(...), ne nad aliasem.
$cm->add('customer', 'Zákazník');
$cm->addEmail('email', 'E-mail');
$cm->addEnum('status', 'Stav', OrderStatus::class);
$cm->addNumber('total_price', 'Celkem', 2, 'Kč');
// Hodnota z poddotazu; chová se jako každý jiný sloupec včetně rozsahového filtru.
$cm->addNumber('item_count', 'Položek', 0);
$cm->addDate('created_at', 'Vytvořeno');
}
public function buttons(ButtonManager $bm): void
{
}
public function rows(Row $row): void
{
}
public function render(): void
{
$this->template->render(__DIR__ . '/SqlJoinGridControl.latte');
}
}
SELECT
o.id AS id,
o.number AS number,
CONCAT(c.first_name, ' ', c.last_name) AS customer,
c.email AS email,
o.status AS status,
o.total_price / 100 AS total_price,
(SELECT COUNT(*) FROM `order_item` oi WHERE oi.id_order = o.id) AS item_count,
o.created_at AS created_at
FROM `order` o
JOIN `customer` c ON c.id = o.id_customer
Výraz za aliasem
Zákazník je CONCAT(c.first_name, ' ', c.last_name) AS customer. Filtr
se poskládá nad výrazem, ne nad aliasem – WHERE CONCAT(…) LIKE ?, protože alias
ve WHERE databáze nepovolí. Hledá se tak rovnou v obou jménech.
Počítaný sloupec
Položek je skalární poddotaz – smí stát ve WHERE i v
ORDER BY, takže má filtr i řazení jako každý jiný sloupec:
(SELECT COUNT(*) FROM `order_item` oi WHERE oi.id_order = o.id) AS item_count
S GROUP BY to nejde. Filtr by postavil
WHERE COUNT(…) = ?, což databáze odmítne. Řešení: skalární poddotaz (jako tady),
databázový pohled, nebo takovému sloupci vypnout filtr přes setFilter(null).