Hlavní navigace

Názory k článku
PHP okénko: Spojování tabulek

Michal Molhanec aura:100

prehlednost

IMHO je bezkonkurencne nejmene prehladna ta varianta uprostred
Jakub Hegenbart aura:84
11. 4. 2005 1:44 Nový

Smysl?

celé vlákno
Nerad bych vypadal zase jako rýpal, ale jaký je smysl pro změnu tohoto článku? Říci, že joiny je lepší svěřit optimalizátoru v DB enginu? Trošku mi to celé připomíná stylem knížku Marka Mazlakowského „Teach Yourself MySQL in 21 days“ (Nejhůř vyhozené peníze, co jsem kdy vydal :( ... měl jsem v tom obchodě déle listovat, než jsem koupil...)
Michal Kubeček
Michal Kubeček (neregistrovaný)
11. 4. 2005 2:16 Nový

Re: Smysl?

celé vlákno
Já hlavně pořád nechápu, proč se to vlastně jmenuje PHP okénko. Tři ze čtyř dosavadních dílů byly čistě o MySQL…
Jakub Vrána aura:60
11. 4. 2005 7:30 Nový

Re: Smysl?

celé vlákno
Texty byly o použití databází v PHP. Předvedeno to bylo na MySQL, ale většina obratů je aplikovatelná i u ostatních databází.
uživatel si přál zůstat v anonymitě
11. 4. 2005 8:59 Nový

Re: Smysl?

celé vlákno
No prave, texty byly o pouziti databazi. S PHP to ma vse spolecne jen to, ze priklady jsou jim obalene.

Ale 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 :)
Petr
Petr (neregistrovaný)
11. 4. 2005 9:57 Nový

Re: Smysl?

celé vlákno
Muzu se zeptat jak se stane ze LEFT JOIN zabije databazi? Dik.
uživatel si přál zůstat v anonymitě
11. 4. 2005 13:20 Nový

Re: Smysl?

celé vlákno
nejak takto:

select * from group_table left join product_table where podminka pres neindexovane polozky;

pri 1000 skupinach 200000 polozkach je to sranda....
Tom
Tom (neregistrovaný)
12. 4. 2005 14:35 Nový

Re: Smysl?

celé vlákno
Pokud to postavíš takhle, tak jedinej, kdo zaslouží zabít je ten člověk, co takovej select pustí...
petr andrs aura:43
11. 4. 2005 21:33 Nový

Re: Smysl?

celé vlákno
Ne, jádrem článku jsou spojení v MySQL, pokud by byl správně pojmenová a oproštěn od PHP balastu, byl by rozhodně mnohem lepší.
Michal Kubeček
Michal Kubeček (neregistrovaný)
11. 4. 2005 22:21 Nový

Re: Smysl?

celé vlákno
Bohužel s vámi nemohu souhlasit. Ukázky používají PHP a MySQL a zatím v těch článcích bylo určitě víc MySQL-specifického než PHP-specifického. Takže bych spíš řekl, že jádrem je MySQL a ukázky jsou sice v PHP, ale většina obratů je snadno aplikovatelná pro jiné programovací jazyky.
Michal Kára
Michal Kára (neregistrovaný)
11. 4. 2005 8:48 Nový

Re: Smysl?

celé vlákno
Budme radi alespon za takoveto clanky. Soude podle ohlasu uzivatelu tady za chvili budou jenom clanky obsahujici nesmyslne placani o nicem...
Jakub Hegenbart aura:84
11. 4. 2005 9:03 Nový

Re: Smysl?

celé vlákno
A to já si nemyslím. Chtělo by to ale pořádný seriál o LISPu nebo Scheme, ideálně o obojím... :)))
Michal Kára
Michal Kára (neregistrovaný)
11. 4. 2005 9:24 Nový

Re: Smysl?

celé vlákno
Nojo, ale proc by se nekdo s nim psal a pak jeste cetl nadavky pod nim na svoji adresu, kdyz muze behem pulhodky napsat clanek nic nerikajicich blabolu? Dostane za to stejne penez a jeste sklidi v diskusi ovace.
Jakub Trávník
Jakub Trávník (neregistrovaný)
11. 4. 2005 11:26 Nový

Re: Smysl?

celé vlákno
Až se budu nudit, tak napíšu ;-) Mám to někde v TODO, ale bohužel moje TODO roste nade všechny meze (naštěstí jen pomalu), tak nevím, kdy to bude.
Jakub Hegenbart aura:84
11. 4. 2005 16:01 Nový

Re: Smysl?

celé vlákno
Klidně třeba zaspolupracuju, ačkoliv se to budu učit takřkajíc za běhu...nějak mne ten jazyk chytnul.

(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)
Petr Bravenec
Petr Bravenec (neregistrovaný)
11. 4. 2005 8:10 Nový

Jako příklad všechny tři varianty odstrašující

celé vlákno

U 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.

Vladimir Kralik
11. 4. 2005 19:50 Nový

Re: Jako příklad všechny tři varianty odstrašující

celé vlákno
> 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.
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.
Petr Bravenec
Petr Bravenec (neregistrovaný)
12. 4. 2005 6:10 Nový

Re: Jako příklad všechny tři varianty odstrašující

celé vlákno
Jo, jasně. Já na všecko používám Postgres, který view zvládá velice dobře - uvedenou podmínku by v tomto jednoduchém konkrétním příkladě aplikoval přímo při výběru dat do view a bylo by to stejně rychlé jako v případě konkrétního dotazu. Postgres jsem se naučil využívat pokud možno co nejvíce. Skutečně to velmi usnadňuje práci. Ovšem view bych nepovažoval za nějakou specialitu. View zvládaly uspokojivě i databáze, se kterými jsem pracoval před více než deseti lety.

Nezá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.
MokrOus
MokrOus (neregistrovaný)
11. 4. 2005 8:48 Nový

LEFT JOIN

celé vlákno
Chtel bych se zeptat, resil jste nekdo pripad, ze mam dve tabulky vhodne pro spojeni zpusobem LEFT JOIN, ale potrebuju vypsat prave(!) ty, pro ktere na druhe strane nenajdu odpovidajici zaznam?
Jestli jo, pisnete to prosim. dik
Jakub Vrána aura:60
11. 4. 2005 8:55 Nový

Re: LEFT JOIN

celé vlákno
Např. "SELECT skupiny.* FROM skupiny LEFT JOIN vyrobky ON skupiny.id = vyrobky.skupina WHERE vyrobky.skupina IS NULL". Šlo by to třeba i přes COUNT(*).
Ján Sokoly
11. 4. 2005 13:36 Nový

Re: LEFT JOIN

celé vlákno
Pochybujem, ze by to slo cez COUNT(*). Ten totiz nikdy nevrati 0. Aspon teda nie v Oracli.
dgx
11. 4. 2005 18:09 Nový

Re: LEFT JOIN

celé vlákno
je třeba jako parametr COUNT použít sloupec z připojované tabulky. Potom by mělo vrátit i nula.
Michal Kubeček
Michal Kubeček (neregistrovaný)
11. 4. 2005 22:15 Nový

Re: LEFT JOIN

celé vlákno
Zajímavé. A co vám tedy vrátí "select count(*) from TBL where 0=1"?
Ján Sokoly
11. 4. 2005 22:25 Nový

Re: LEFT JOIN

celé vlákno
Takto isto ano. Ale aj v pripade, ze COUNT(*) pouzijete v podmienke WHERE?
Michal Kubeček
Michal Kubeček (neregistrovaný)
12. 4. 2005 4:00 Nový

Re: LEFT JOIN

celé vlákno

Neví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ý.

Ján Sokoly
12. 4. 2005 9:12 Nový

Re: LEFT JOIN

celé vlákno
Na mysli som mal
... WHERE COUNT(*) = 0;
Michal Kubeček
Michal Kubeček (neregistrovaný)
12. 4. 2005 12:33 Nový

Re: LEFT JOIN

celé vlákno
Taková klauzule mi moc nedává smysl, ale budu předpokládat, že myslíte spíš "having 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ě.
Petr Bravenec
Petr Bravenec (neregistrovaný)
11. 4. 2005 9:36 Nový

Re: LEFT JOIN

celé vlákno
select * from skupiny where id not in (select skupina from vyrobky)
BigSam
BigSam (neregistrovaný)
11. 4. 2005 9:04 Nový

Nechci urazit autora

celé vlákno
ale ten clanek je naprosto o hovne ...
dave
dave (neregistrovaný)
11. 4. 2005 11:20 Nový

Re: Nechci urazit autora

celé vlákno
svata pravda
martin
martin (neregistrovaný)
11. 4. 2005 11:24 Nový

OT - ukázky kódu a posuvníky

celé vlákno
Když už má root vyřešeno zobrazování kusů kódu tak jak má, pak by to měl autor článku brát v úvahu a rozdělit přiklady na krátké úseky.

Protož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.
MMM
MMM (neregistrovaný)
11. 4. 2005 14:27 Nový

Re: OT - ukázky kódu a posuvníky

celé vlákno
Souhlas, ja vzdy kdyz chci videt (v konqueroru) nejaky zdrojovy kod, musim kopirovat pres schranku :/
AraxoN
AraxoN (neregistrovaný)
11. 4. 2005 13:05 Nový

...

celé vlákno
Pozerám že sa na autora zniesla spŕška kritiky. A úplne oprávnene! K už povedanému dodám už len námietku voči zásade číslo 3.:

-- 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.
Jakub Vrána aura:60
11. 4. 2005 13:15 Nový

Re: ...

celé vlákno

Můž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.

dave
dave (neregistrovaný)
11. 4. 2005 13:27 Nový

Re: ...

celé vlákno
u DB2 zalezi na nastaveni stupne optimalizace, jinak to databaze vykona tak jak to napisete. Je to obecny problem, protoze optimalizator v tu chvili nemusi byt schopen najit nejlepsi cestu.
AraxoN
AraxoN (neregistrovaný)
11. 4. 2005 16:03 Nový

Re: ...

celé vlákno
Po pravde, netuším čo k tomu hovorí dokumentácia, ale moje skúsenosti sú také ako som napísal. Možno to neplatí paušálne, ale od istej doby som sa odnaučil písať joiny takto natvrdo. Možno to bola vina konkrétneho DB enginu - snažil som sa teraz chvíľku reprodukovať toto správanie pod MySQL 4.1 a Postgres 7.3 - a nepodarilo sa...
Ivo
Ivo (neregistrovaný)
11. 4. 2005 14:41 Nový

Re: ...

celé vlákno
Podla mna je poutitie WHERE ovela prehladnejsie ako JOIN.
uživatel si přál zůstat v anonymitě
11. 4. 2005 15:26 Nový

Re: ...

celé vlákno
Podla mna je poutitie JOIN ovela prehladnejsie ako WHERE.
HKMaly aura:99

Re: ...

celé vlákno
Podle me je pro prehlednost dulezite, jestli to programator napise na jeden 300 znakovy radek, nebo do nekolika radku a treba rovnou s komentari (mysleno PHP komentari, ne SQL). Takova prkotina jako rozdil mezi tim, jestli je podminka join nalevo nebo napravo od where uz nic nevyresi.
gemda
gemda (neregistrovaný)
11. 4. 2005 20:46 Nový

forum

celé vlákno
hello, aj ja mam pocit ze sa viac pise o mysql ako o php, a system zobrazovania ukazkoveho kodu je dost krkolomny, ale cert to ber.

Nahodou 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
uživatel si přál zůstat v anonymitě
12. 4. 2005 8:40 Nový

Re: forum

celé vlákno
No, ja tiez nie som expert ako vsetci ostatni diskutujuci, ale riesil by som to asi takto:

select 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).
Jakub Vrána aura:60
12. 4. 2005 11:59 Nový

Re: forum

celé vlákno
V první řadě vaší pozornosti doporučuji článek http://www.root.cz/clanky/stromy/ nebo http://interval.cz/clanek.asp?article=3801. Asi by bylo lepší přizpůsobit strukturu databáze.
Zasílat nově přidané příspěvky e-mailem