Autor Zpráva
Jcas
Profil *
Chtěl bych poprosit o radu "jak se to dělá?" Narazil jsem na určitou nejasnost při spojování tabulek.
Dotaz
Vypiš všechna zvířata chovatele a vypiš všechny vlastnosti. Pokud má k vlastnosti přiřazena data, tak je vypiš taky a pokud ne, tak vypiš null. (tabulky jsou v odkazu)


V tomto dotazu chybí jeden řádek. Spojení `zv_data` a `zvirata_vlastnosti`.
    $sql = "SELECT `chovy`.*, `zvirata`.*, `zv_data`.*, `zvirata_vlastnosti`.* 
    FROM `chovy`
    JOIN `zvirata` ON `chovy`.`id_zvire` = `zvirata`.`id_zvirete` 
    JOIN `zv_data` ON `chovy`.`id_chovu` = `zv_data`.`id_chov`
    LEFT JOIN ??????????
    WHERE `chovy`.`id_chovatel` = $id_user";

Napřed jsem myslel, že jednoduše pomocí LEFT-RIGHT zajistím vypsání všech vlastností i když u nich nebudou data.
Ta nejasnost, kterou momentálně mám:
- připojuji tabulky k tabulce `chovy`. Jak nastavím vazbu LEFT-RIGHT mezi `zv_data` a `zvirata_vlastnosti`?

Napadají mne pouze dva nezávislé dotazy a pak to nějak spárovat. Ale mám tušení, že by to mělo jít (a že se to tak dělá-je to lepší) jedním dotazem.

DB (pdf)
Alphard
Profil
Tam je jednoduchá vazba 1:M, takže stačí normální left join.
left join zvirata_vlastnosti zv on zv_data.id_vlastnost = zv.id_vlastnosti
Jcas
Profil *
Já to nechápu.
ON - vnímám něco jako podmínku WHERE
FROM `chovy` LEFT JOIN `zvirata_vlastnosti` - jak lze spojit tabulky, když vazba mezi nimi neexistuje?
juriad
Profil
Ty nepřipojuješ tabulky k chovu, ale připojuješ tabulky k tomu chuchvalci.
(chovy JOIN zvirata) je jakoby pseudotabulka, která má sloupce z tabulky chovy i z tabulky zvirata
((chovy JOIN zvirata) JOIN zv_data) je jakoby pseudotabulka, která má sloupce jak z pseudotabulky (chovy JOIN zvirata), tak i z tabulky zv_data.
Není to tedy hvězda, že se všechno připojuje k chovu, ale postupně se to nabaluje. Snad to trochu znázorní tento obrázek:


A teď si zkus představit, že neuvedeš žádné vazební podmínky, v takovém případě prostě spojí každý záznam v jedné tabulce s každým záznamem v druhé tabulce. Pokud měla první tabulka A záznamů a druhá B záznamů, po spojení bude ta pseudotabulka bez podmínky mít A*B záznamů. Slyšel jsi něco o kartézském součinu?
Ale ty nechceš všechny, chceš jen některé, takže uvedeš nějaké podmínky, které musí platit. A teď si představ, že těch tabulek pospojuješ bez podmínek hodně, vznikne něco nepředstavitelně velikého (bude to jedna obří pseudotabulka). Ale ty můžeš přidat podmínku mezi libovolné sloupce bez ohledu na to, z které tabulky původně pocházely.

Snad jsem ti tvou představu příliš nezamotal.
Jcas
Profil *
super: Děkuji


Lze do toho dotazu strčit ještě něco jako EXISTS?
Pokud v `chovy` nic není, tak nemá cenu dál něco vybírat.
Původně jsem si myslel, že tuto situaci odchytím tak, jestli se něco vybere, nebo ne. Ale tím, že si vytahuji všechny vlastnosti, tak to takhle nejde.
mlasevic
Profil
Myslím, že podle toho, co píšeš, tak použití funkce EXISTS je zcela zbytečné. To bys musel asi řešit nejdříve dotazem, jestli v CHOVY vůbec něco je pomocí EXISTS a pak teprve vlastní vnořený dotaz. Příjde mi to jako zcela zbytečné a rovnou bych psal ten dotaz s joinem na vlastnosti.
Jcas
Profil
Nějak mi to nefunguje. Sice si asi dokážu vysvětlit proč, ale nevím jak to udělat, aby to chodilo.
Vyberu zvířata a chovy daného chovatele-to je ok. Ale ke každému zvířeti chci vypsat všechna vlastnosti z `zvirata_vlastnosti`a k nim buď null, nebo hodnotu.
Tori
Profil
Jestli pořád máte na začátku tohle: SELECT `chovy`.*, `zvirata`.*, `zv_data`.*, `zvirata_vlastnosti`.* , tak by to chtělo doplnit aliasy pro stejnojmenné sloupce, které se vyskytují v několika tabulkách. Např. sloupec hodnota je jak ve zv_data, tak zvirata_vlastnosti, takže na výstupu nejspíš dostanete jen jeden sloupec s hodnotou zvirata_vlastnosti.hodnota - ten druhý ("černá", "bílá",...) se jím přepíše.
Jinak na výstupu bude pro každou vlastnost jeden řádek záznamů - tj. ostatní údaje o zvířeti, chovu atd. se budou opakovat.

Jestli tohle není příčina problému, tak nějak upřesněte to "Nějak mi to nefunguje."
Btw, v jakém programu je udělané to schéma DB návrhu? Vypadá to pěkně.
Jcas
Profil
Tori:
Btw, v jakém programu je udělané to schéma DB návrhu? Vypadá to pěkně. Nechtělo se mi hledat program na udělání návrhu DB a taky hledat jestli je zdarma. Ten můj návrh je udělán ručně v tabulce.

Sloupec zvirata.vlastnosti.hodnota jsem přejmenoval na vlastnost (zapomněl dokreslit do obr.)
abych neměl duplicitu.
To efunguje neznamená, že je něco špatně. To znamená, že pro výsledek jaký chci potřebuji jiný dotaz, nebo jej nějak upravit.

Zatím mám toto
    $sql = "SELECT `chovy`.*, `zvirata`.*, `zv_data`.*, `zvirata_vlastnosti`.* 
    FROM `chovy`
    JOIN `zvirata` ON `chovy`.`id_zvire` = `zvirata`.`id_zvirete` 
    LEFT JOIN `zv_data` ON `chovy`.`id_chovu` = `zv_data`.`id_chov`
    LEFT JOIN `zvirata_vlastnosti` ON `zv_data`.`id_vlastnost` = `zvirata_vlastnosti`.`id_vlastnosti` 
    WHERE `chovy`.`id_chovatel` = $id_user 
    ORDER BY `zvirata`.`skupina`, `zvirata`.`zvire`, `zvirata`.`plemeno` ";
ve zv_data to nenajde nic a tak zv_vl nevypíše taky ani jednu. Ale jak ten dotaz poskládat, aby to ty vlastnosti vypsalo všechny?
Jcas
Profil
Toto se tváří, že se chová tak jak chci. Ale je to roztržení do dvou dotazů, tak nevím jestli je to správná cesta.
    $sql = "SELECT `chovy`.*, `zvirata`.*
    FROM `chovy`
    JOIN `zvirata` ON `chovy`.`id_zvire` = `zvirata`.`id_zvirete` 
    WHERE `chovy`.`id_chovatel` = $id_user 
    ORDER BY `zvirata`.`skupina`, `zvirata`.`zvire`, `zvirata`.`plemeno` ";
    
    if($result = $mysqli->query($sql)) {
        
        while($row = $result->fetch_assoc()) {
            $html = implode('  |  ', $row);
            echo '<p>'.$html.'</p>';
            
            $que = "SELECT `zv_vl`.*, `d`.* FROM `zvirata_vlastnosti` `zv_vl`
            LEFT JOIN `zv_data` `d` ON `zv_vl`.`id_vlastnosti` = `d`.`id_vlastnost`
            WHERE `d`.`id_chov` = ".$row['id_chovu']." OR `d`.`id_chov` IS NULL ";
            $res = $mysqli->query($que);
            while($rw = $res->fetch_assoc()) { 
                echo '<p>';
                echo 'vlastnost <strong>'.$rw['id_vlastnosti'].'</strong>:  <strong>'.$rw['vlastnost'].'</strong> - ná hodnotu: ';
                echo $rw['hodnota'];
                echo '</p>'; 
            }    
            $res->close();
            
        } 

        $result->close();
    }  else { echo $mysqli->error;}
juriad
Profil
Podle mě chceš dotaz:
SELECT *
FROM chovy c
JOIN zvirata z ON c.id_zvire = z.id_zvirete
CROSS JOIN zvirata_vlastnosti v
LEFT JOIN zv_data d ON c.id_chovu = d.id_chov AND v.id_vlastnosti = d.id_vlastnost

To klíčové slovo CROSS tam není nutné, slouží jen pro „dokumentaci“, že se spojují záznamy bez podmínky - tedy ke každému chovu všechny vlastnosti.
Jcas
Profil
Dobrý díky

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0