<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="cs">
	<id>http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=LEFT_INNER_JOIN_%28en%29</id>
	<title>LEFT INNER JOIN (en) - Historie editací</title>
	<link rel="self" type="application/atom+xml" href="http://postgres.cz/index.php?action=history&amp;feed=atom&amp;title=LEFT_INNER_JOIN_%28en%29"/>
	<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=LEFT_INNER_JOIN_(en)&amp;action=history"/>
	<updated>2026-05-12T23:43:59Z</updated>
	<subtitle>Historie editací této stránky</subtitle>
	<generator>MediaWiki 1.43.3</generator>
	<entry>
		<id>http://postgres.cz/index.php?title=LEFT_INNER_JOIN_(en)&amp;diff=518&amp;oldid=prev</id>
		<title>imported&gt;Pavel: /* INNER JOIN (vnitřní spojení) */</title>
		<link rel="alternate" type="text/html" href="http://postgres.cz/index.php?title=LEFT_INNER_JOIN_(en)&amp;diff=518&amp;oldid=prev"/>
		<updated>2012-02-24T09:45:11Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;INNER JOIN (vnitřní spojení)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nová stránka&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[Category:Articles]]&lt;br /&gt;
OUTER JOIN (LEFT or RIGHT) is probably most complex clause of SELECT statement. A beginners&lt;br /&gt;
that can use this clause can use SQL well. Little bit more difficult corelated subqueries are &lt;br /&gt;
not necessary now and with some luck anobody doesn&amp;#039;t use it. But using of JOINs is every day&lt;br /&gt;
work for SQL coder. This article is oriented to beginners (with really basic knowleadge of SQL).&lt;br /&gt;
&lt;br /&gt;
==Prolog, Statement SELECT==&lt;br /&gt;
SELECT statement is basic fundament of SQL. It is hard to believe what wide spectrum of tasks should&lt;br /&gt;
be solved with this simple statement. SELECT is divided into optional clauses. Order of clauses is &lt;br /&gt;
important. Some clause is used when it is necessary.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT &amp;lt;expression list&amp;gt;     -- expression can be reference to some column&lt;br /&gt;
   FROM &amp;lt;source relations&amp;gt;           -- tables, derivated tables&lt;br /&gt;
  WHERE &amp;lt;predicates&amp;gt;         -- only rows with true predicates are showed&lt;br /&gt;
  GROUP BY &amp;lt;expression list&amp;gt; -- specify subsets for agrregates&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There are some other clauses (HAVING, ORDER BY, LIMIT, ...), but these not used in this article,&lt;br /&gt;
and it is reason why it missing here.&lt;br /&gt;
&lt;br /&gt;
==Normalisation==&lt;br /&gt;
One from basic principles of relation databases is a saving data in separated&lt;br /&gt;
tables. This is described by so called normal forms. There was more motivations,&lt;br /&gt;
some should be effective using of persistent media (there are no redundant data)&lt;br /&gt;
and some unnecessary overwriting is minimized. Current hardware is really different,&lt;br /&gt;
but these old requests and principles are same. &lt;br /&gt;
&lt;br /&gt;
Not well normalized tables can break a performance and it is signal not well designed&lt;br /&gt;
databases. Using of wide tables can decrease speed of sequential scan, because it&lt;br /&gt;
implicate a reading of unwanted data. Using too wide tables can increase a complexity&lt;br /&gt;
of updates data.&lt;br /&gt;
&lt;br /&gt;
These requests are not valid for OLAP (analytical) databases. There are some special&lt;br /&gt;
engines (column databases) usually and there are a minimal requests for random updating of data. &lt;br /&gt;
&lt;br /&gt;
So data in relation databases are in more tables usually. And we have to be able to &lt;br /&gt;
join data to one result. SELECT statement can do it simply and effectively.&lt;br /&gt;
&lt;br /&gt;
==Primary Keys and Foreign keys==&lt;br /&gt;
There are simple and composite keys. Simple keys are related to one column, composite keys are based on more columns.&lt;br /&gt;
In this article we will use only simple keys. Primary key is column, that identifies exactly one row in table. Foreign &lt;br /&gt;
key is column with values that can specify rows from other table (usual use case) or from same table.&lt;br /&gt;
&lt;br /&gt;
Example (Author, Book)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Relation Authors (id, name, surname)  .. id is primary key of relation Authors&lt;br /&gt;
Relation Books(id, author_id, name) ... id is primary key of relation Authors, author_id is foreign key to relation Authors&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
When author_id&amp;#039;s value is 10, then this book was written by author with id 10.&lt;br /&gt;
&lt;br /&gt;
Older relation databases enables join of tables only on PK,FK relations. SQL is not too strict. JOIN is not limited. It &lt;br /&gt;
is strong tool, but it should be source of some strange errors too. So beginners should be used on JOINs based on PK,FK&lt;br /&gt;
keys.&lt;br /&gt;
&lt;br /&gt;
==Predicate==&lt;br /&gt;
Predicate is a expression with result true or false. You can use it in WHERE clause usually.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT name, surname, age &lt;br /&gt;
   FROM Staff&lt;br /&gt;
  WHERE age &amp;gt;= 30;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Predicate &amp;quot;age &amp;gt;= 30&amp;quot; is true for some subset of employees. This is filter for result. Only these&lt;br /&gt;
employees will be in result.&lt;br /&gt;
&lt;br /&gt;
Predicates can be composed with boolean operators AND, OR. When predicates is in form (column operator value),&lt;br /&gt;
then planner can use it as index parameter. So:&lt;br /&gt;
* well a &amp;gt; b, wrong a + 1 &amp;gt; b + 1,&lt;br /&gt;
* well a &amp;gt; 10, wrong a + 5 &amp;gt; 15&lt;br /&gt;
&lt;br /&gt;
==Cartesian product==&lt;br /&gt;
Cartesian product is one form of merging two relations (some other are: sum, difference, intersection, ..). Result of Cartesian product are all possible combination items from related sets. Cartesian product is possible for tables too, but only subset of Cartesian product has sense. SQL creates Cartesian product for all tables (relations) from WHERE clause. Example: When table Author has 5 rows and table Books 10 rows, then result will have 50 rows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT * &lt;br /&gt;
  FROM Authors, Books;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
that is complete Cartesian product of tables Author and Books.&lt;br /&gt;
&lt;br /&gt;
==INNER JOIN==&lt;br /&gt;
Is good style to separate predicates related to table&amp;#039;s joining and predicates related to&lt;br /&gt;
WHERE clause. This separation is available via JOIN keyword.&lt;br /&gt;
&lt;br /&gt;
Note: SQL has not tools for query semantic validation. Badly created query can be correct&lt;br /&gt;
from syntax view, but wrong from semantic view - it can returns wrong (messy) result. Sometimes&lt;br /&gt;
final user can identify these problems - because he is missing some data, or he see some data&lt;br /&gt;
more times. Structured notation (like Joe Celko&amp;#039;s notation) can decrease a number of errors.&lt;br /&gt;
&lt;br /&gt;
INNER JOIN is most simple variant of JOIN (Note: INNER and OUTER keywords are optional and these keywords&lt;br /&gt;
are not used usually). The result of JOIN is Cartesian product filtered by predicate.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT title, surname, name&lt;br /&gt;
   FROM Books&lt;br /&gt;
        JOIN&lt;br /&gt;
        Authors&lt;br /&gt;
        ON Books.author_id = Authors.id&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Look on predicate. This predicate shows a relation between primary key and foreign key. The query&lt;br /&gt;
shows book&amp;#039;s title and name and surname of Book&amp;#039;s author. When we would to books written by one &lt;br /&gt;
author, we can to modify query:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT title, surname, name&lt;br /&gt;
   FROM Books&lt;br /&gt;
        JOIN&lt;br /&gt;
        Authors&lt;br /&gt;
        ON Books.author_id = Authors.id&lt;br /&gt;
  WHERE surname = &amp;#039;Capek&amp;#039;&lt;br /&gt;
    AND name = &amp;#039;Jan&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
There are two predicates in two clauses. Older notation used only WHERE clause for predicates:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT title, surname, name&lt;br /&gt;
   FROM Books, Authors&lt;br /&gt;
  WHERE Books.author_id = Authors.id&lt;br /&gt;
    AND surname = &amp;#039;Capek&amp;#039;&lt;br /&gt;
    AND name = &amp;#039;Jan&amp;#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This query is simple and readable. But more complex queries was badly written sometimes. Missing&lt;br /&gt;
predicates for joining can produce very slow and expensive query - using JOIN keyword is good&lt;br /&gt;
protection again this kind of errors.&lt;br /&gt;
&lt;br /&gt;
==Rychlost==&lt;br /&gt;
Ohledně efektivity operace slučování tabulek koluje neuvěřitelné množství mýtů a fám. &lt;br /&gt;
Většina programátorů používala SQL, aniž by do hloubky rozuměli technologii a docela&lt;br /&gt;
často zaměňovali příčinu s důsledkem. Na vině byly i ne zcela dotažené a odladěné&lt;br /&gt;
databáze.&lt;br /&gt;
&lt;br /&gt;
* není žádný rozdíl ve výkonnosti mezi použitím JOINu a původním zápisem pro spojení tabulek. Pamatuji doby, kdy se JOIN nepoužíval právě z obavy o ztrátu výkonu. To je nesmysl. Liší se pouze zápis. Smysl a provádění je stejné.&lt;br /&gt;
* nehraje roli jaké sloupce spojujete (jestli jsou nebo nejsou primárním či cizím klíčem), ale je důležité, jestli na těchto sloupcích je index, a zda-li si typově odpovídají spojované sloupce v predikátu (jinak se musí v každém řádku provádět konverze, což má nemalou režii). Nad sloupcem primárního klíče se vždy vytváří unikátní index. Některé databáze ještě automaticky vytváří index i nad sloupci s cizími klíči. Indexy zásadně urychlují spojení tabulek. To nezůstalo bez povšimnutí programátorů. Výsledkem je fáma, že efektivita spojení závisí na referenční integritě. Nezávisí. Závisí na indexech. Indexy na cizím klíči automaticky vytváří např. Firebird (naopak PostgreSQL je nevytváří).&lt;br /&gt;
&lt;br /&gt;
Databázový administrátor by neměl podlehnout pokušení indexovat každý sloupec dat &lt;br /&gt;
v databázi. Hledá se kompromis, který je platný pro určitou aplikaci, firmu, dobu. &lt;br /&gt;
Platí totiž, že každý index způsobí zpomalení operací INSERT, UPDATE, DELETE. Kromě &lt;br /&gt;
vlastní změny dat se ještě musí aktualizovat všechny indexy nad tabulkou. Čím jich &lt;br /&gt;
je více, tím to déle trvá.&lt;br /&gt;
&lt;br /&gt;
Pozn.: Ještě dlouho, co už to dávno nebyla pravda, se tradovalo, že JOIN není &lt;br /&gt;
přenositelný. RDBMS Oracle totiž, kromě JOINu, nabídla a nabízí vlastní zápis pro &lt;br /&gt;
OUTER JOIN. Nicméně jak INNER, tak OUTER JOIN je (už skoro deset let) součástí &lt;br /&gt;
standardu a všechny významné SQL RDBMS obsahují podporu této klauzule.&lt;br /&gt;
&lt;br /&gt;
==OUTER JOIN (vnější spojení)==&lt;br /&gt;
Představte si databázi, kde máte tabulku zaměstnanců a tabulku obsahující evidenci&lt;br /&gt;
pracovní neschopnosti zaměstnanců. Pokud Vás zajímá, který zaměstnanec byl v pracovní&lt;br /&gt;
neschopnosti, tak použijete INNER JOIN. Ten zobrazuje spárované záznamy. Mám záznam&lt;br /&gt;
jak v tabulce zaměstnanců, tak v tabulce pracovní neschopnosti. Pokud by Vás zajímali&lt;br /&gt;
všichni zaměstnanci nebo jen ti, kteří byli stále zdraví (tudíž nemají záznam v tabulce&lt;br /&gt;
pracovní neschopnosti), INNER JOIN Vám nepomůže. Prostě Vám záznamy těchto zaměstnanců&lt;br /&gt;
nezobrazí. Příklad: Chceme zobrazit všechny zaměstnance a jejich počet hodin v &lt;br /&gt;
pracovní neschopnosti:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Zamestanci(id, jmeno, prijmeni)&lt;br /&gt;
PracovniNeschopnosti(id, zam_id, den, pocet)&lt;br /&gt;
&lt;br /&gt;
-- jednoduchá varianta, zobrazí záznamy pro ty, kteří mají záznam&lt;br /&gt;
-- v tabulce PracovniNeschopnosti&lt;br /&gt;
SELECT jmeno, prijmeni, pocet&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        JOIN (SELECT zam_id, sum(pocet) AS pocet&lt;br /&gt;
                 FROM PracovniNeschopnosti&lt;br /&gt;
                GROUP BY zam_id) s&lt;br /&gt;
        ON z.id = s.zam_id; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Tuto úlohu řeší OUTER JOIN. Jednoduše doplní výsledek tak, aby obsahovala celou&lt;br /&gt;
tabulku uvedenou nalevo od klíčového slova JOIN (LEFT JOIN) nebo napravo (RIGHT JOIN).&lt;br /&gt;
Nově přidané řádky zákonitě musí někde obsahovat jakousi vatu. Například Zaměstnanec,&lt;br /&gt;
který nikdy nebyl nemocný, nemůže mít přiřazenou hodnotu sum(pocet). Tou vatou je&lt;br /&gt;
hodnota NULL. Takže v další iteraci by náš dotaz vypadal takto:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT jmeno, prijmeni, pocet&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        LEFT JOIN (SELECT zam_id, sum(pocet) AS pocet&lt;br /&gt;
                      FROM PracovniNeschopnosti&lt;br /&gt;
                     GROUP BY zam_id) s&lt;br /&gt;
        ON z.id = s.zam_id; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Kdybyste si dali tu práci a příklad přepsali a vyzkoušeli, tak zjistíte, že to ještě&lt;br /&gt;
není ono. U trvale zdravých zaměstnanců se nezobrazuje nula, ale prázdný řetězec&lt;br /&gt;
neboli NULL. To už je drobnost. Použijeme funkci COALESCE, která slouží k náhradě&lt;br /&gt;
NULL za libovolnou jinou hodnotu.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT jmeno, prijmeni, coalesce(pocet, 0)&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        LEFT JOIN (SELECT zam_id, sum(pocet) AS pocet&lt;br /&gt;
                      FROM PracovniNeschopnosti&lt;br /&gt;
                     GROUP BY zam_id) s&lt;br /&gt;
        ON z.id = s.zam_id; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Je důležité mít na paměti, že OUTER JOIN je podstatně náročnější na provádění než&lt;br /&gt;
INNER JOIN, a tudíž jej používat jen tehdy, když je třeba. OUTER JOIN zapsaný bez &lt;br /&gt;
klauzule JOIN může mít tuto podobu:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT jmeno, prijmeni, 0 -- vždy zdraví zaměstnanci&lt;br /&gt;
   FROM Zamestnanci &lt;br /&gt;
  WHERE id NOT IN (SELECT zam_id &lt;br /&gt;
                      FROM PracovniNeschopnosti)&lt;br /&gt;
UNION ALL&lt;br /&gt;
SELECT jmeno, prijmeni, pocet  -- zaměstnanci se záznamem&lt;br /&gt;
   FROM Zamestnanci z, &lt;br /&gt;
        (SELECT zam_id, sum(pocet) AS pocet&lt;br /&gt;
            FROM PracovniNeschopnosti&lt;br /&gt;
           GROUP BY zam_id) s&lt;br /&gt;
  WHERE z.id = s.zam_id;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Často se OUTER JOIN používá pro vyhledání něčeho co někde není v kombinaci s operátorem &lt;br /&gt;
IS NULL. Výpis všech vždy zdravých zaměstnanců lze provést dotazem:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT jmeno, prijmeni, pocet&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        LEFT JOIN &lt;br /&gt;
        PracovniNeschopnosti p&lt;br /&gt;
        ON z.id = p.zam_id&lt;br /&gt;
  WHERE pocet IS NULL;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Tento dotaz lze také přepsat s použitím poddotazu (případně korelovaného poddotazu).&lt;br /&gt;
Opět záleží na aplikaci a datech, která varianta bude nejefektivnější:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- klasický dotaz&lt;br /&gt;
SELECT jmeno, prijmeni&lt;br /&gt;
   FROM Zamestnanci&lt;br /&gt;
  WHERE id NOT IN (SELECT zam_id&lt;br /&gt;
                      FROM PracovniNeschopnosti);&lt;br /&gt;
&lt;br /&gt;
SELECT jmeno, primeni&lt;br /&gt;
   FROM Zamestnanci&lt;br /&gt;
  WHERE id &amp;lt;&amp;gt; ALL (SELECT zam_id &lt;br /&gt;
                      FROM PracovniNeschopnosti);&lt;br /&gt;
&lt;br /&gt;
-- korelovaný poddotaz (pouze pro úplnost, až na výjimky nebude tím optimálním)&lt;br /&gt;
SELECT jmeno, prijmeni&lt;br /&gt;
   FROM Zamestnanci&lt;br /&gt;
  WHERE NOT EXISTS (SELECT id &lt;br /&gt;
                       FROM PracovniNeschopnosti&lt;br /&gt;
                      WHERE zam_id = Zamestnanci.id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Pozn.: V některých databázích je zjevná asymetrie&lt;br /&gt;
v rychlosti zpracování LEFT OUTER JOINu a RIGHT OUTER JOINu (výhodnější je používat &lt;br /&gt;
LEFT JOIN). Některé databáze RIGHT JOIN nemají implementován (SQLite). Jiné databáze&lt;br /&gt;
tyto problémy nemají (PostgreSQL).&lt;br /&gt;
&lt;br /&gt;
Několik poznámek na konec. Přesun GROUP BY do derivované tabulky je jedním z triků,&lt;br /&gt;
které urychlují provádění dotazů. Platí, že čím víc sloupců klauzule GROUP BY obsahuje, tím je její zpracování pomalejší a vyžaduje více paměti. V příkladu navíc&lt;br /&gt;
dochází ke spojení skutečné a derivované (odvozené) tabulky. To ve starších před SQL&lt;br /&gt;
databázích nešlo. Následující příklad demonstruje právě tuto vlastnost SQL. Spojují&lt;br /&gt;
se dvě tabulky na základě složeného predikátu. Jedná se o &amp;quot;klasický&amp;quot; příklad zobrazení&lt;br /&gt;
zaměstnanců s nejvyšší mzdou v rámci oddělení. Tento vzor se opakuje v řadě SQL &lt;br /&gt;
úloh.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Zamestanci(id, oddeleni_id, jmeno, prijmeni, mzda)&lt;br /&gt;
Oddeleni(id, nazev) &lt;br /&gt;
&lt;br /&gt;
-- složený predikát&lt;br /&gt;
SELECT jmeno, prijmeni, mzda, nazev&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        JOIN (SELECT oddeleni_id, max(mzda) AS max_mzda&lt;br /&gt;
                 FROM Zemestnanci&lt;br /&gt;
                GROUP BY oddeleni_id) s&lt;br /&gt;
        ON z.oddeleni_id = s.oddeleni_id AND z.mzda = s.max_mzda&lt;br /&gt;
        JOIN&lt;br /&gt;
        Oddeleni o&lt;br /&gt;
        ON o.id = z.oddeleni_id;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
nebo&lt;br /&gt;
Jelikož se JOIN použil pouze k filtrování záznamů, lze předchozí dotaz převést&lt;br /&gt;
do tvaru s poddotazem:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- jednoduchý predikát s binárním operátorem rovnost řádků&lt;br /&gt;
SELECT jmeno, prijmeni, mzda, nazev&lt;br /&gt;
   FROM Zamestnanci z&lt;br /&gt;
        JOIN &lt;br /&gt;
        Oddeleni o&lt;br /&gt;
        ON o.id = z.oddeleni_id&lt;br /&gt;
  WHERE (z.oddeleni_id, z.mzda) = (SELECT oddeleni_id, max(mzda)&lt;br /&gt;
                                      FROM Zamestnanci&lt;br /&gt;
                                     GROUP BY oddeleni_id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Konečně další možností je použití korelovaného poddotazu. Výsledky obou výše uvedených&lt;br /&gt;
dotazů jsou stejné. Odlišný je však jejich prováděcí plán, tudíž i doba zpracování. &lt;br /&gt;
A opět záleží na skutečných datech, která varianta bude optimální. Volba optimální&lt;br /&gt;
varianty je jedním z mála způsobů jak ovlivnit zpracování SQL příkazu. Svou roli tu&lt;br /&gt;
hraje i použitá databáze. To co je optimální pro MySQL, nemusí být optimální pro&lt;br /&gt;
PostgreSQL nebo Firebird (a naopak). A aby to bylo ještě o něco komplikovanější,&lt;br /&gt;
záleží i na konfiguraci serveru (na velikosti přidělené paměti).&lt;br /&gt;
&lt;br /&gt;
==FULL JOIN and CROSS JOIN==&lt;br /&gt;
FULL JOIN ensures so all rows from both related relations are included in result of join operation. A usage of this variant of JOIN is not often. CROSS JOIN is inner JOIN where any rows from one table is joined with any row from second table. This form of JOIN was used in old times for some very special tasks (row numbering). These old patterns are not readable and fast usually - SQL has a better tools now (in almost all cases - window analytic functions).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  Staff CROSS JOIN Departments ~ Staff JOIN Departments ON true&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==SELF JOIN==&lt;br /&gt;
Jako SELF JOIN se označuje obyčejně INNER JOIN, který má na obou stranách tutéž &lt;br /&gt;
tabulku. Je to technika, která se používala k obejití chybějící funkcionality v SQL&lt;br /&gt;
(takovou typickou úlohou, kterou v SQL92 jednoduše nevyřešíte, je výpočet klouzavých průměrů).&lt;br /&gt;
Výhodou řešení založených na SELF JOINech je přenositelnost, nevýhodou rychlost.&lt;br /&gt;
Moderní databáze podporují tzv. analytické dotazy, které umožňují efektivně řešit &lt;br /&gt;
úlohy, které se řešily SELF JOINem. Pokud nejsou k dispozici analytické dotazy,&lt;br /&gt;
pak se obvykle vyplatí použít uložené procedury. Náročnost&lt;br /&gt;
na zpracování není možná ani tou hlavní nevýhodou. Jedná se o absolutní alchymii &lt;br /&gt;
jakoby opsanou z testů Mensy. Zdaleka nejvíc se s touto technikou setkáte v SQL&lt;br /&gt;
kvízech Joe Celka (asi jediná osoba na planetě, která tyto věci dokáže vymyslet).  &lt;br /&gt;
&lt;br /&gt;
Rozšířenou ukázkou je číslování řádků ve výpisu. Předpokládejme, že id zaměstnanců&lt;br /&gt;
netvoří souvislou řadu, nicméně požadujeme, aby každý řádek měl své pořadové číslo&lt;br /&gt;
(Ve starších verzích SQL bylo striktně dodržováno pravidlo, že o zobrazení se stará&lt;br /&gt;
aplikace. Tudíž i o číslování řádků).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT count(*), z1.jmeno, z1.prijmeni&lt;br /&gt;
   FROM Zamestnanci z1&lt;br /&gt;
        JOIN&lt;br /&gt;
        Zamestnanci z2&lt;br /&gt;
        ON z1.id &amp;gt;= z2.id&lt;br /&gt;
  GROUP BY z1.jmeno, z1.prijmeni; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Suquery, correlated subquery , derivated tables==&lt;br /&gt;
SELECT statement can includes other (nested) SELECT statements. When nested SELECT is used in FROM clause,&lt;br /&gt;
then we call it as &amp;quot;derivated table&amp;quot;. For other usage we use a &amp;quot;subquery&amp;quot; term. Nested SELECT can has a link&lt;br /&gt;
(alias) to outer query - then we use a term &amp;quot;correlated subquery&amp;quot;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- show all employees from Administration department &lt;br /&gt;
SELECT * &lt;br /&gt;
  FROM Staff&lt;br /&gt;
 WHERE dep_id = (SELECT id                          -- subquery&lt;br /&gt;
                         FROM Departments &lt;br /&gt;
                        WHERE name = &amp;#039;Administration&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
-- returns a employees with biggest salary from each department &lt;br /&gt;
-- with using correlated subquery&lt;br /&gt;
SELECT * &lt;br /&gt;
   FROM Staff o -          - alias &lt;br /&gt;
  WHERE salary = (SELECT max(salary)&lt;br /&gt;
                   FROM Staff&lt;br /&gt;
                  WHERE dep_id = o.dep_id); -- correlated subquery&lt;br /&gt;
&lt;br /&gt;
-- returns a employees with biggest salary from each department&lt;br /&gt;
-- with using derivated table&lt;br /&gt;
SELECT s.*&lt;br /&gt;
   FROM Staff s&lt;br /&gt;
        JOIN (SELECT dep_id, max(salary) AS max_salary,&lt;br /&gt;
                 FROM Staff&lt;br /&gt;
                GROUP BY dep_id) d&lt;br /&gt;
        ON s.dep_id = d.dep_id AND s.salary = d.max_salary;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In almost all cases SELECT with correlated subqueries will be slower, but there are a few tasks&lt;br /&gt;
where correlated subqueries are necessary (depends on database system and supported features. Windows&lt;br /&gt;
analytical functions or derivated tables can replace correlated subqueries usually). &lt;br /&gt;
&lt;br /&gt;
Queries with JOINs are simply. It is not hard work. There are not reason why use a some sophisticated &lt;br /&gt;
designers or libraries usually. So use it.&lt;/div&gt;</summary>
		<author><name>imported&gt;Pavel</name></author>
	</entry>
</feed>