Názory k článku
PHP okénko: Spojování tabulek
Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoAle to neresme - bylo mozna vhodne zminit, ze LEFT (RIGHT) JOIN vam pri spatnem pouziti zabije databazi. Krome toho kdyz se obcas koukam na mnoho php programatoru, tak si rikam, ze misto prikladu na LEFT JOIN by se jim hodil priklad na EXPLAIN :)
Ale ty clanky s PHP opravdu nesouvisi a jejich nazev jim samotnym skodi. Uz treba kvuli vyhledavani, jehoz relevance se snizuje. Pokud budu hledat neco o PHP, vyskoci na me db. A kdyz budu hledat neco o db, toto mozna vubec nenajdu.
SEO odbornici by vam utrhli hlavu :)
Re: Smysl?
celé vláknoRe: Smysl?
celé vláknoselect * from group_table left join product_table where podminka pres neindexovane polozky;
pri 1000 skupinach 200000 polozkach je to sranda....
Re: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vláknoRe: Smysl?
celé vlákno(Chytnul i mého výrobce harf, takže si můžeme pomáhat navzájem...on mně naučí stavět harfy a já jemu zase pomůžu s lambdami :DDD)
Jako příklad všechny tři varianty odstrašující
celé vláknoU takto jednoduchého příkladu se to dá omluvit, ale pokud to má být "ukázkový" příklad, pak je to naprostá trotlovina. Velké množství dotazů se používá na několika místech - jednou se ze stejných dat generuje třeba ceník pro internetového uživatele, podruhé se ze stejných dat generuje ceník pro prodejce, doplněný o možnosti změn. Pro podobné příklady bych použil zásadně VIEW. To je předem připravený dotaz, uložený přímo v databázi, a na všech místech programu poskytující pokaždé stejná data. Pokud se později provádějí změny do struktury tabulek, stačí opravit dotaz na jediném místě - v databázi - a do programů se promítnou změny bez zásahu programátorovy ruky.
Takže "odstrašující řešení" je skutečně odstrašující, "za určitých okolností přijatelné řešení" je odstrašující a nakonec "správné řešení" je v kontextu ukázkového příkladu taky odstrašující.
Vzorový příklad by měl vypadat v databázi takto:
CREATE VIEW vyrobky_view AS SELECT vyrobky.id, vyrobky.nazev, skupiny.nazev AS skupina_nazev FROM vyrobky INNER JOIN skupiny ON vyrobky.skupina = skupiny.id
a v PHP takto:
// správné řešení
$result = mysql_query("SELECT * FROM vyrobky_view WHERE podminka");
while ($row = mysql_fetch_assoc($result)) {
echo "<a href='?id=$row[id]'>$row[nazev]</a>"
.($row[skupina_nazev])<br/>\n";
}
mysql_free_result($result);
Pokud databáze MySQL nezvládá VIEW, pak by se na projekty, obsahující více než jednu tabulku, vůbec neměla používat.
Re: Jako příklad všechny tři varianty odstrašující
celé vlákno> obsahující více než jednu tabulku, vůbec neměla používat.
Neviem ako MySQL, poznam (trochu) Informix.
Tam sice VIEW existuje, ale s jeho realnym pouzitim je to horsie :-(.
Uvedeny priklad by Informix realizoval na dva kroky takto :
"""select * from vyrobky_view where podmienka"""
1.) vytvor join vo vyrobky_view do docasnej tabulky
2.) na docasnu tabulku aplikuj "podmienku"
V pripade, ze join vyrobky X skupiny da niekolko miliononov riadkov, tak sa vysledku nedockate, hoci "podmienka" vyberie iba par riadkov.
> Pro podobné příklady bych použil zásadně VIEW.
Ak si chcem zachovat nezavislost od pouzitej DB, tak sa nebudem spoliehat na ziadne specialitky z DB-servera a na strane aplikacneho servera si zakryjem DB-vrstvu vhodnym objektovym mapovanim. V mojom pripade (Java) je riesenim Hibernate.
Re: Jako příklad všechny tři varianty odstrašující
celé vláknoNezávislost na použité databázi je možná pěkná věc, ale zeptám se takto: kolik lidí vytváří aplikace, které musí běhat nezávisle na SQL stroji v Postgresu, Ingresu, Accessu, MySQL a Foxpro? "Nezávislost" je u drtivé většiny programátorů výmluva, aby se nemuseli učit nic složitého a mohli jít s davem.
LEFT JOIN
celé vláknoJestli jo, pisnete to prosim. dik
Re: LEFT JOIN
celé vláknoRe: LEFT JOIN
celé vláknoRe: LEFT JOIN
celé vláknoRe: LEFT JOIN
celé vláknoselect count(*) from TBL where 0=1"?
Re: LEFT JOIN
celé vláknoRe: LEFT JOIN
celé vláknoNevím, co máte přesně na mysli, ale u Firebirda mi
select ... from TBL1 A where (select count(*) from TBL2 B where B.COL2=A.COL1)=0
dá přesně totéž, co (podstatně vhodnější)
select ... from TBL1 A where not exists (select * from TBL2 B where B.COL2=A.COL1)
nebo
select ... from TBL1 A left join TBL2 B on B.COL2=A.COL1 where B.COL2 is null
a nedokážu si dost dobře představit, proč by měl být výsledek různý.
Re: LEFT JOIN
celé vláknohaving count(*)=0". Pak to samozřejmě nemůže fungovat, protože u left join bude ve výsledku vždy minimálně jeden řádek a u inner join nebude sice žádný, ale pak taky nebude co dát do result set. Ale vaše původní tvrzení, že pomocí count(*) to nejde, není určitě pravdivé; jde to, jen se musí použít správně.
Re: LEFT JOIN
celé vláknoNechci urazit autora
celé vláknoOT - ukázky kódu a posuvníky
celé vláknoProtože pokud je úsek kódu příliš dlouhý (tak že se nevejde na výšku na obrazovku), pak nelze rozumně ten kód prozkoumat. Jedině takto idiotsky: sjet se stránkoou, až se ukáže horizontální posuvník, posunout, vyjet se stránkou až se ukáže kód, zjistit že jsme popojeli málo, zopakovat, zjistit že jsme popojeli moc, zopakovat atd. atd....
Řešení - vkládat pouze několikařádkové ukázky, anebo stanovit maximální výšku a případně zobrazit i vertikální posuvník kódu.
Re: OT - ukázky kódu a posuvníky
celé vlákno...
celé vlákno-- citujem --
3. Pro spojení tabulek se dá používat i zápis FROM vyrobky, skupiny WHERE vyrobky.skupina = skupiny.id. Tento zápis osobně nemám rád, protože dochází ke smíchání spojovacích a ostatních podmínek, což je nepřehledné obzvláště při větším množství spojovaných tabulek.
-- Koniec citátu --
Hlavne pri väčšom počte joinovaných tabuliek a zložitejšej WHERE podmienke nad rôznymi tabuľkami je práve tento zápis najrozumnejší, lebo poradie joinovania optimalizuje DB engine obvykle lepšie než to zvládne programátor, hlavne ak WHERE zostavujeme dynamicky podľa nejakých vyhľadávacích kritérií, čo zadá užívateľ. Pri joinovaní cez kľúčové slovo JOIN zároveň určujeme aj poradie v akom sa joinuje, a to môže databázu úplne zložiť na kolená už pri relatívne malom objeme dát.
Re: ...
celé vláknoMůžete čtenáře odkázat např. na relevantní část dokumentace, která by dokazovala vaše tvrzení, že použitím klíčového slova JOIN se určuje pořadí, v jakém se joinuje? Např. v MySQL popisu JOIN je uvedeno:
STRAIGHT_JOIN is identical to JOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.
Z toho mi vychází, že u normálního JOINu si databáze pořadí tabulek určí sama. Navíc si nemyslím, že by to byla nějaká MySQL-specifická věc.
Re: ...
celé vláknoRe: ...
celé vláknoRe: ...
celé vláknoRe: ...
celé vláknoRe: ...
celé vláknoforum
celé vláknoNahodou mam otazku (ak mozem) pretoze som nedavno riesil zobrazovanie poloziek po skupinach len trochu v inom pripade a nakoniec som nevyuzil ziadnu podobnu moznost ako je tu v clanku resp. v odpovediach, hoci som vyskusal naozaj kopu moznosti.
Moja situacia:
Vytvaral som tabulku pre obycajne web-forum. Chcel som aby sa jeho zlozky dali rozlozit do 4roch skupin. Kategoria, Sekcia, Forum a nakoniec samotne Prispevky vo forach. Jednoducho aby ked navstevnik dorazi na moje forum najprv uvidel Sekcie For zgrupene v Kategoriach. Potom ako klikne na nejaku sekciu zobrazi sa mu zoznam For z tejto sekcie a ked klikne na forum tak uvidi jeho Prispevky. Dufam ze sa to da pochopit :)
Druhou mojou poziadavkou bolo aby sa to dalo vsetko natlacit do jednej tabulky. Jedine ak by som chcel robit nieco ako permissions... tak na to by som potreboval dalsiu tabulku, ale o to nejde.
takze som navrhol takuto tabulku "forum" (pouzivam MySQL 4.0???)
-------
id INT PRIMARY KEY AUTO_INCREMENT *** ako identifikacne cislo polozky
level TINYINT *** tento parameter by niesol informaciu o tom ci je polozka kategoriou(level=0) sekciou(level=1) forom(level=2) alebo prispevkom(level=3)
owner INT *** uchova informaciu rodicovskej polozky, cize pre Sekcie to bude NULL lebo su najvyssimi moznymi jednotkami v hierarchii ale pre ostatne 3 typy spomenutych poloziek to bude prislusna referencia na "id" parameter v tejto tabulke.
title TEXT, content TEXT, time DATETIME *** uz spominam len pre pripad ze by som ich niekde potreboval spomenut, podstatne su len prve tri parametre (id,level a owner)
------
takze ked uzivatel dorazi do mojho fora chcel som aby ako prve uvidel nieco take jednoduche ako:
Kategoria 1
-- Sekcia 1
-- Sekcia 2
-- Sekcia 3
Kategoria 2
-- Sekcia 1
-- Sekcia 2
Kategoria 3
-- Sekcia 1
-- Sekcia 2
-- Sekcia 3
-- Sekcia 4
atd.
Najprv som si myslel ze moj problem vyriesi obycajny SELECT s pouzitim GROUP BY. Nieco ako:
SELECT * FROM forum WHERE level=0 OR level=1 GROUP BY level,owner.
v skutocnosti som vyskusal mnoho kombinacii takehoto podobneho zapisu (myslim zmenou columnov v podmienkach), ale nic z toho nefungovalo tak ako som si to prial, ziadne grupenie sa nekonalo, vlastne ked sa nad tym zamyslim tak ani neviem podla coho by mala databaza vediet ze podla coho mala jednotky grupovat. Co viedlo k tomu ze vlastne ani neviem na co parameter GROUP BY sluzi a co v konecnom dosledku akurat svedci o tom ze som neschopny sa ucit vyznamu funkcii :))) nevadi.
chcel som zistit ci sa daju na tento ucel pouzit aj JOIN funkcie ale tam sa opat potvrdila moja neschopnost rozumiet funkciam, asi je to na moj mozog too much :)
zufalo som sa pokusal zakomponovat aj flow control podmienky ako IF, ktore po niekolko hodinovom badani tiez neviem ako a naco pouzit :)) vobec v nejakom pripade... smutne
zamyslal som sa aj nad zverenim tejto grupovacej ulohy na bremena php ale to by si zrejme vyzadovalo plnenie nejakeho pola kopou dat a potom ich zoradovat hhmmmm, tak som to viacmenej natrvalo zamietol
a asi za 24 hodin tazkeho badania, som po stovkach upravach pociatocneho selektu, zakomponovani funkcie UNION a obycajneho aliasingu nasiel sposob ako moje Kategorie a Sekcie zobrazit pekne vygrupene a to iba v jednom query s tym ze php ich uz dostane pekne vygrupene:
(SELECT *,id AS arrange WHERE level=0 ORDER BY title ASC) UNION (SELECT *,owner AS arrange WHERE level=1 ORDER BY title ASC) ORDER BY arrange;
Cize vysledkom je jedna tabulka kde sa vykonaju dva selekty z tej istej tabulky, pricom v prvom selekte sa vyberu vsetky kategorie tentokrat zoradene abecedne podla nazvu(title) a v druhom selekte sa vyberu vsetky sekcie tiez zoradene podla nazvu, pricom sa (zrejme) oba selekty vykonaju nasledne ale do tej istej vyslednej tabulky. Nakoniec sa ale zoradia podla novovzniknuteho stlpca arrange ktory vlastne vedie iba cisla ownerov bez ohladu na to ci je to polozka nadradenej kategorie alebo podradenej sekcie. Mozno vas teraz napadla otazka preco by vlastne malo byt vsetko zoradene tak ako si to prajem ked sa tabulka zoraduje podla arrange, co ak sa kategoria strati medzi svojimi detmi vo vyslednom liste? nestrati sa, bude vzdy prva, pretoze prvy selekt vyberal prave kategorie a druhy prave sekcie, preto budu kategorie vzdy "akoby nadradene" sekciam, a teda sa zobrazia najprv, a potom ich sekcie.
Samozrejme ze nechcem vzdy aby boli Kategorie radene podla nazvu alfabeticky vzostupne tak som este neskor dotvoril stlpec "ordernum INT" podla ktoreho potom riesim ORDER BY podla prednastavenych cisel.
A teraz moja otazka:
Aj napriek tomu ze toto riesenie prevedie iba dva selekty a plne splni moju poziadavku, nezda sa mi to uplne orechove. Moje znalosti o databazach su velmi biedne ako vidite, a tak prosim ak mozte a hlavne VIETE, tak prosim poradte ako zriesit taky isty vystup pouzitim spajania tabuliek (neviem ktore JOIN by to malo byt) s uvedenim presneho query podla parametrov ake som tu nacrtol. Alebo aspon spomente co je nie dobre na tom mojom selecte.
Ale ak nieste poradna tak sa ospravedlnujem za zbytocne otravovanie.
Dakujem
Re: forum
celé vláknoselect kat.id, kat.nazov, sek.id, sek.nazov
from test as kat
left join test as sek on sek.owner=kat.id
where kat.level=0
Left join koli tomu, aby sa vypisali aj kategorie, ktore nemaju sekcie...
Samozrejme este treba spravit index nad owner (a level).

