<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="./sproject_html.xsl"?>
<!DOCTYPE sproject SYSTEM "sproject.dtd">
<sproject>
    <course database="Oracle" version="11">
        <cname>Databázové systémy</cname>
            <code>BI-DBS.21</code>
            <semester>B212</semester>
            <seminar>LS 2021/22</seminar>
    </course>
        <author>
            <aname>Jan Černý</aname>
        </author>
    <content>
        <declaration>Prohlašuji, že jsem svou semestrální práci vypracoval samostatně. Všechny zdroje, ze kterých jsem čerpal, jsou uvedeny v části Zdroje.</declaration>
            <title>Kariérní portál</title>
        <description>
            <title>Popis</title>
                    <para>ICT oddělení ČVUT se rozhodlo vytvořit nový webový portál pro kariérní spolupráci firem a studentů FITu. Firmy na tomto portále budou mít možnost vkládat programátorská zadání a zakázky na tvorbu různých aplikací a projektů, které pak budou moci studenti vypracovávat a budovat si tak svoje portfolio a praxi.</para>
                    <para></para>
                    <para>Nejdříve bude potřeba uchovávat <b>Uživatele</b> (<b>Account</b>, protože &quot;user&quot; je chráněné  klíčové slovo). U něj budeme evidovat především <i>jméno</i> a <i>přijímení</i>, <i>username</i> a zahashované <i>heslo</i>, případně <i>seznam programovacích jazyků</i>, ve kterých se orientuje. Také bude moct získávat <i>ocenění</i> (achievemenety) za splnění různých úkolů.</para>
                    <para></para>
                    <para><b>Programovací jazyk</b> (<b>Language</b>) bude mít pouze svůj <i>název</i>. Dále lze rozšířit jako programovací jazyk uživatele (u kterého lze uchovávat <i>verzi</i> a uživatelovu <i>zkušenost</i> s tímto jazykem), či programovací jazyk projektu (pouze <i>verzi</i>).</para>
                    <para></para>
                    <para><b>Ocenění</b> (<b>Achievement</b>) má krátký <i>název</i> a <i>popis</i> úkolu, který je potřeba splnit pro jeho získání.</para>
                    <para></para>
                    <para>Pro vložení nových zakázek (projektů) je potřeba založit firemní profil. Každá <b>Společnost</b> (<b>Organization</b>) má svůj <i>název</i>,  kontaktní <i>mail</i>, a vybraný <i>seznam uživatelů</i>(moderátorů), kteří ji mohou spravovat a vytvářet k ní projekty. Také je možné k ní vkládat <i>komentáře</i>, jako například nějaké hodnocení/recenze společnosti. Každá společnost je spravována/moderována alespoň jedním uživatelem.</para>
                    <para></para>
                    <para><b>Komentář</b> (<b>Comment</b>) obsahuje <i>uživatele</i>, který ho napsal, a samotný text s <i>obsahem</i>. Na komentáře je možné i odpovídat jiným komentářem, tedy každý komentář může být odpovědí na jiný komentář. Proto k němu budeme evidovat i jeho<i>rodičovský komentář</i>, pokud nějaký má. Zároveň je třeba zajistit, aby nemohl být rodičem sám sobě. Komentář je buďto odpovědí a nebo &quot;root&quot; komentářem k nějaké společnosti.</para>
                    <para></para>
                    <para>Při vytváření nového <b>Projektu</b> (<b>Project</b>) je potřeba vyplnit jeho <i>název</i> a <i>popis</i>, požadované <i>datum dokončení</i> (deadline) a <i>programovací jazyk</i>. Dále budeme evidovat <i>datum vložení</i>, které se automaticky doplní, <i>název firmy</i> která jej vytvořila, <i>seznam studentů</i> kteří na něm aktuálně pracují, soubory <i>příloh</i>, a <i>stav projektu</i> (pravděpodobně nějaký enum nebo check, může být &quot;nový&quot; pro nově vložené projekty, &quot;ve vývoji&quot; pro aktuálně řešené projekty, a &quot;dokončený&quot; pro projekty hotové).</para>
                    <para></para>
                    <para><b>Příloha</b> (<b>Attachment</b>) má čitelný <i>titulek</i>, který se zobrazí uživatelům, <i>uživatele</i> který ji nahrál, <i>odkaz</i> na stažení, <i>hash</i> nahraného souboru, <i>datum nahrání</i> a přiřazený <i>projekt</i>, ke kterému patří. Každá příloha může být připřazena pouze k jednomu projektu, ale projekt může mít mnoho příloh.</para>
        </description>
        <data_model>
            <title>Conceptual schema</title>
            <dm_picture>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="conceptual_schema.png"/>
                    </imageobject>
                </mediaobject>
            </dm_picture>
            <dm_discussion>
                        <para><h4>Smyčka <b>Comment ― Comment</b>:</h4></para>
                        <para>Jedná se o komentář k organizaci anebo komentář může být odpovědí na jiný komentář.  Komentář může mít více odpovědí, ale sám odpovídat pouze na 1 jiný. Zde by mohl vzniknout problém, kde by komentář byl odpovědí sám sobě, zavádíme tedy <b>IO1</b>.</para>
                        <para>XOR je použitý k tomu, aby komentář mohl být buď pouze &quot;root komentářem&quot; daného vlákna u nějaké organizace, a nebo pouze odpovědí na jiný komentář v tomto vlákně.</para>
                        <para></para>
                        <para></para>
                        <para><h4>Smyčka <b>Account ― Organization ― Project ― Account</b>:</h4></para>
                        <para>Uživatel může být zároveň správcem organizace, která založila nějaký projekt, a zároveň může na daném projektu pracovat jako vývojář. Pokud bychom chtěli správcům organizace zamezit pracovat na jejích projektech, bylo by nutné zavést IO. My tuto situaci připouštíme.</para>
                        <para></para>
                        <para></para>
                        <para><h4>Smyčka <b>Account ― Comment ― Organization ― Account</b>:</h4></para>
                        <para>Uživatelé mohou k organizacím přidávat komentáře. Někteří uživatelé ale mohou být zároveň správci této organizace. Jedná se o podobnou situaci jako ve smyčce výše, my správcům dovolíme psát komentáře k vlastní organizaci.</para>
                        <para></para>
                        <para></para>
                        <para><h4>Smyčka <b>Account ― Account_language ― Language_type ― Project_language ― Project-Account</b>:</h4></para>
                        <para>Uživatel by mohl mít vazbu (pracovat) na projektu psaném v programovacím jazyce, který ale uživatel neumí/nemá zapsaný. To nás ale nemusí trápit, protože uživatel může na projektu dělat i jiné než jen programovací práce (konzultant, grafik...) a tak nemusí mít zapsaný programovací jazyk.</para>
                        <para></para>
                        <para></para>
                        <para>Dalších podobných smyček se ve schématu nachází více, ale logicky se jedná o podobné problémy, které byly již vysvětleny, nebo prodloužení již popsané smyčky přes další entitu.</para>
            </dm_discussion>
        </data_model>
        <relational_model>
            <title>Relační schema</title>
            <rm_picture>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="relational_schema.png"/>
                    </imageobject>
                </mediaobject>
            </rm_picture>
        </relational_model>
        <queries>
            <title>Dotazy</title>
            <dotazy>
                    <dotaz dotaz_id="D1">
                        <popis_dotazu>
                                <para>Vyber 10 nejnovějších (dle datumu) projektů, které mají state jako &#039;new&#039;.</para>
                        </popis_dotazu>
                            <sql>SELECT * FROM project
WHERE state = &#039;new&#039;
ORDER BY creation_date DESC
LIMIT 10;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D2">
                        <popis_dotazu>
                                <para>Vyber všechny organizace, které ještě nezaložily žádný projekt.</para>
                        </popis_dotazu>
                            <relacni_algebra>{ organization[organization_id] \ project[organization_id] } *&gt; organization</relacni_algebra>
                            <sql>SELECT * FROM organization
JOIN 
(
    SELECT organization_id FROM organization
    EXCEPT
    SELECT organization_id FROM project
) orgs_without_projects USING (organization_id);
</sql>
                    </dotaz>
                    <dotaz dotaz_id="D3">
                        <popis_dotazu>
                                <para>Vyber všechny projekty, na kterých se podílel uživatel s ID 1.</para>
                        </popis_dotazu>
                            <relacni_algebra>account_project(account_id=1)*&gt;project</relacni_algebra>
                            <sql>SELECT project.* FROM project
JOIN account_project USING (project_id)
WHERE account_id = 1;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D4">
                        <popis_dotazu>
                                <para>Vyber uživatele, který pracuje na všech existujících projektech.</para>
                        </popis_dotazu>
                            <relacni_algebra>{account_project[account_id, project_id] ÷ project[project_id]} *&gt; account</relacni_algebra>
                            <sql>-- Pomoci COUNTu
SELECT * FROM account WHERE 
    (
        SELECT COUNT(DISTINCT project_id) FROM account_project
        WHERE account_project.account_id = account.account_id
    )
    =
    (
        SELECT COUNT(project_id) FROM project
    )
;

-- Pomoci WHERE NOT EXISTS
-- SELECT * FROM account a WHERE NOT EXISTS
-- (
--     SELECT * FROM project p WHERE NOT EXISTS
--     (
--         SELECT * FROM account_project ap WHERE ap.account_id=a.account_id AND ap.project_id=p.project_id 
--     )
-- );</sql>
                    </dotaz>
                    <dotaz dotaz_id="D5">
                        <popis_dotazu>
                                <para>Vyber všechny uživatele, kteří pracovali pouze na projektu s ID 1.</para>
                        </popis_dotazu>
                            <relacni_algebra>account_project(project_id = 1) *&gt; account</relacni_algebra>
                            <sql>SELECT account.* FROM account
JOIN account_project ON(account.account_id = account_project.account_id)
WHERE project_id = 1</sql>
                    </dotaz>
                    <dotaz dotaz_id="D6">
                        <popis_dotazu>
                                <para>Vyber všechny komentáře uživatele s ID 1, které napsal ke společnosti s ID 69.</para>
                        </popis_dotazu>
                            <relacni_algebra>comment(account_id=1 ∧ organization_id=69)[comment_id,content]</relacni_algebra>
                            <sql>SELECT  comment_id, content FROM COMMENT
WHERE account_id = 1 AND organization_id = 69;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D7">
                        <popis_dotazu>
                                <para>Vyber všechny komentáře, které jsou přímou odpovědí na komentář s ID 8.</para>
                        </popis_dotazu>
                            <relacni_algebra>comment(parent_comment_id=8)[account_id,content]</relacni_algebra>
                            <sql>SELECT  account_id,
        content
FROM COMMENT
WHERE parent_comment_id = 8;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D8">
                        <popis_dotazu>
                                <para>Zjisti, v jaké verzi programovacího jazyku C# umí uživatel s ID 9 pracovat. (Vyber verzi z jazyka C# uživatele s ID 9)</para>
                        </popis_dotazu>
                            <relacni_algebra>{account_language(account_id=9)*language_type(name=&#039;C#&#039;)}[version]</relacni_algebra>
                            <sql>SELECT version FROM account_language
JOIN
(
    SELECT language_type_id FROM language_type
    WHERE name = &#039;C#&#039;
) language_csharp USING (language_type_id)
WHERE account_id = 9;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D9">
                        <popis_dotazu>
                                <para>Vyber nejnovější přílohu u projektu s ID 3 a vypiš její titulek a odkaz ke stažení.</para>
                        </popis_dotazu>
                            <sql>SELECT  title, download_link FROM attachment
WHERE project_id = 3
ORDER BY uploaded_on DESC
LIMIT 1;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D10">
                        <popis_dotazu>
                                <para>Vyber nejstarší projekt v jazyce C#, který má stále ještě stav jako &quot;nový&quot;.</para>
                        </popis_dotazu>
                            <sql>SELECT * FROM project
JOIN project_language USING (project_id)
WHERE state = &#039;new&#039; AND language_type_id = (
    SELECT language_type_id FROM language_type
    WHERE name = &#039;C#&#039;
)
ORDER BY creation_date DESC
LIMIT 1;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D11">
                        <popis_dotazu>
                                <para>Vyber všechny komentáře uživatele s emailem &#039;jurkov24@dropbox.com&#039;, které napsal ke společnosti s ID 69.</para>
                        </popis_dotazu>
                            <relacni_algebra>{account(email=&#039;jurkov24@dropbox.com&#039;)[account_id]*
comment(organization_id=69)}[comment_id,content]</relacni_algebra>
                    </dotaz>
                    <dotaz dotaz_id="D12">
                        <popis_dotazu>
                                <para>Ověření dotazu D4, očekáváme prázdný výsledek.
(D4: Vyber uživatele, který pracuje na všech existujících projektech.)</para>
                        </popis_dotazu>
                            <relacni_algebra>project
\
{{account_project[account_id, project_id]÷project[project_id]}*account*&gt;account_project*&gt;project}</relacni_algebra>
                            <sql>-- Vybereme z M:N relace &#039;account_project&#039; takove uzivatele, kteri maji relaci se vsemi projekty
SELECT account_id, COUNT(DISTINCT account_project.project_id) FROM account_project
WHERE account_id IN
(
    -- Vybereme pouze takova account_id, kterej maji relaci se vsemi projekty
    SELECT account_id FROM
    (
        -- Overovana cast (tedy dotaz cislo D4, ktery je kat. D1)
        SELECT * FROM account WHERE
        (
            SELECT COUNT(DISTINCT project_id) FROM account_project
            WHERE account_project.account_id = account.account_id
        )
        =
        (
            SELECT COUNT(project_id) FROM project
        )
        -- Konec overovane casti
    ) accounts_with_all_projects
 )

GROUP BY account_id

-- Omezime vyber pouze na takove ucty, ktere nemaji stejny pocet projektu jako je vsech projektu
-- (tedy na ty, ktere nemaji relaci se vsemi)
HAVING COUNT(DISTINCT account_project.project_id) != (SELECT COUNT(project_id) FROM project);</sql>
                    </dotaz>
                    <dotaz dotaz_id="D13">
                        <popis_dotazu>
                                <para>Vyber uživatele, kteří pracují na nějakém rozpracovném projektu (project.state =  &#039;ongoing&#039;)</para>
                        </popis_dotazu>
                            <relacni_algebra>{account_project * project(state=&#039;ongoing&#039;)} *&gt; account</relacni_algebra>
                            <sql>SELECT DISTINCT account.* FROM account
JOIN account_project USING(account_id)
JOIN project USING (project_id)
WHERE project.state = &#039;ongoing&#039;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D14">
                        <popis_dotazu>
                                <para>Vyber uživatele, kteří aktuálně NEpracují na žádném rozpracovném projektu (project.state =  &#039;ongoing&#039;)</para>
                        </popis_dotazu>
                            <relacni_algebra>{account \ {project(state=&#039;ongoing&#039;) [project.project_id = account_project.project_id&gt; account_project [account_project.account_id = account.account_id&gt; account}}
[first_name, last_name, email]</relacni_algebra>
                            <sql>SELECT first_name, last_name, email FROM account

EXCEPT

SELECT first_name, last_name, email FROM account
    JOIN account_project ON (account.account_id = account_project.account_id)
    JOIN project USING (project_id)
    WHERE project.state = &#039;ongoing&#039;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D15">
                        <popis_dotazu>
                                <para>Vyber 10 uživatelů s největším počtem založených projektů, spočítej jejich počet a vypiš ve sloupečku projects_count.</para>
                        </popis_dotazu>
                            <sql>SELECT account.account_id, account.first_name, account.last_name, account.email, counted_accounts.count AS projects_count FROM
(
    -- Vyber account_id a ke kazdemu spocitej pocet projektu
    SELECT DISTINCT account_id, COUNT (account_id) FROM account_project
    JOIN project USING (project_id)
    GROUP BY account_id

) AS counted_accounts
    
    
-- Spoj s tabulkou account, pro ziskani dalsich atributu
JOIN account USING (account_id)

-- Serad podle poctu
ORDER BY counted_accounts.count DESC

LIMIT 10</sql>
                    </dotaz>
                    <dotaz dotaz_id="D16">
                        <popis_dotazu>
                                <para>Vyber 5 uživatelů, kteří získali nejvíce achievementů, spočítej jejich počet a vypiš ve sloupečku achievements_count.</para>
                        </popis_dotazu>
                            <sql>SELECT account.account_id, account.first_name, account.last_name, account.email, counted_achievements.count AS achievements_count FROM
(
    -- Vyber account_id a ke kazdemu spocitej pocet achievementu
    SELECT DISTINCT account_id, COUNT(account_id) FROM achievement
    JOIN achievement_type USING (achievement_type_id)
    GROUP BY account_id
    
) AS counted_achievements
    
-- Spoj s tabulkou account, pro ziskani dalsich atributu
JOIN account USING (account_id)

-- Serad podle poctu
ORDER BY counted_achievements.count DESC

LIMIT 10</sql>
                    </dotaz>
                    <dotaz dotaz_id="D17">
                        <popis_dotazu>
                                <para>Vyber všechny organizace, které ještě nezaložily žádný projekt. (Antijoinem)</para>
                        </popis_dotazu>
                            <relacni_algebra>project ![project.organization_id = organization.organization_id&gt; organization</relacni_algebra>
                            <sql>SELECT DISTINCT * FROM organization
WHERE NOT EXISTS
(
    SELECT * FROM project
    WHERE project.organization_id = organization.organization_id
)</sql>
                    </dotaz>
                    <dotaz dotaz_id="D18">
                        <popis_dotazu>
                                <para>Vyber všechny uživatele, kteří nikdy nepracovali na žádném projektu. (Antijonem)</para>
                        </popis_dotazu>
                            <relacni_algebra>account_project !*&gt; account</relacni_algebra>
                            <sql>SELECT DISTINCT * FROM account a
WHERE NOT EXISTS
(
    SELECT * FROM account_project ap
    WHERE ap.account_id = a.account_id
)</sql>
                    </dotaz>
                    <dotaz dotaz_id="D19">
                        <popis_dotazu>
                                <para>Odstraň všechny projekty, které už jsou po své deadlině (tedy deadline_date &lt; dnešní datum).</para>
                        </popis_dotazu>
                            <sql>BEGIN;

-- Zkontrolujeme, ze poddotaz vraci potrebna project_id, ktera jsou rozhodujici pro budouci smazani.
-- Tim otestujeme dotaz, a vime, kolik toho budeme mazat
SELECT COUNT(project_id) from project
WHERE deadline_date &lt; CURRENT_DATE;

-- Provedeme smazani s podminkou IN
DELETE FROM project
WHERE project_id IN
(
    SELECT project_id from project
    WHERE deadline_date &lt; CURRENT_DATE
);

-- Overime, zda bylo mazani uspesne, ocekavame 0 vysledku
SELECT COUNT(project_id) from project
WHERE deadline_date &lt; CURRENT_DATE;

ROLLBACK;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D20">
                        <popis_dotazu>
                                <para>Vyber všechny projekty, které majít stav jako &#039;new&#039; nebo &#039;ongoing&#039;.</para>
                        </popis_dotazu>
                            <relacni_algebra>project(state=&#039;new&#039;) ∪ project(state=&#039;ongoing&#039;)</relacni_algebra>
                            <sql>-- Pomoci UNION (RA: project(state=&#039;new&#039;) ∪ project(state=&#039;ongoing&#039;))
SELECT DISTINCT * FROM project
WHERE state = &#039;new&#039;

UNION

SELECT DISTINCT * FROM project
WHERE state = &#039;ongoing&#039;;

-- Pomoci WHERE OR (RA: project(state=&#039;new&#039; ∨ state=&#039;ongoing&#039;))
SELECT DISTINCT *
FROM project
WHERE (state = &#039;new&#039; OR state = &#039;ongoing&#039;);

-- Pomoci EXCEPT (RA: project \ project(state=&#039;complete&#039;))
SELECT DISTINCT *
FROM project

EXCEPT

SELECT DISTINCT *
FROM project
WHERE (state=&#039;complete&#039;);</sql>
                    </dotaz>
                    <dotaz dotaz_id="D23">
                        <popis_dotazu>
                                <para>Vytvoř view s názvem &#039;overdue_projects&#039;, do kterého vyber zpožděné projekty. (Zpožděný projekt je takový, který stále má stav &#039;ongoing&#039; a již překročil svou deadline)</para>
                        </popis_dotazu>
                            <sql>CREATE OR REPLACE VIEW overdue_projects AS

    SELECT * FROM project
    WHERE (state=&#039;ongoing&#039; AND deadline_date &lt; CURRENT_DATE)
        
WITH CHECK OPTION;

-- Provedeni kontroly, ze VIEW funguje
SELECT * FROM overdue_projects</sql>
                    </dotaz>
                    <dotaz dotaz_id="D24">
                        <popis_dotazu>
                                <para>Smaž všechny zpožděné projekty (viz dotaz D23).</para>
                        </popis_dotazu>
                            <sql>BEGIN;

-- Zkontrolujeme, ze poddotaz vraci potrebna project_id, ktera jsou rozhodujici pro budouci smazani.
-- Tim otestujeme dotaz, a vime, kolik toho budeme mazat
SELECT COUNT(*) from overdue_projects;

-- Provedeme smazani
DELETE FROM project
WHERE EXISTS
(
    SELECT * FROM overdue_projects
);

-- Overime, zda bylo mazani uspesne, ocekavame 0 vysledku
SELECT COUNT(*) FROM overdue_projects;

ROLLBACK;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D25">
                        <popis_dotazu>
                                <para>Jaký je pro každého uživatele jeho nejstarší projekt (dle creation_date), na kterém pracoval?
Pokud na žádném nepracoval, chceme mít ve výpisu informaci &#039;&lt;NO PROJECT&gt;&#039;.
Ve výstupu chceme ID uživatele, jméno, email; seřazeno podle nejstarších projektů a poté ID uživatele.</para>
                        </popis_dotazu>
                            <sql>SELECT  account.account_id,
        account.first_name,
        account.last_name,
        account.email,
        COALESCE( TO_CHAR(MIN(project.creation_date),&#039;dd.mm.yyyy&#039;), &#039;&lt;NO PROJECT&gt;&#039; ) AS oldest_project
        -- COALESCE = nahradi NULL hodnoty za &#039;&lt;NO PROJECT&gt;&#039;&#039;
        -- TO_CHAR = prevede &#039;creation_date&#039; do formatu &#039;dd.mm.yyyy&#039;
        -- MIN = vybere nejstarsi &#039;creation_date&#039;
        
FROM account
    LEFT JOIN account_project ON account.account_id = account_project.account_id
    LEFT JOIN project USING(project_id)

GROUP BY account.account_id, account.first_name, account.last_name, account.email
ORDER BY oldest_project, account.account_id;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D26">
                        <popis_dotazu>
                                <para>Kolik záznamů by měla tabulka achievementů, pokud by každý uživatel obdržel achievement od každého druhu?</para>
                        </popis_dotazu>
                            <sql>-- Zjistime pocet uzivatelu
SELECT COUNT(*)
FROM account;

-- Zjistime pocet dostupnych druhu achievementu
SELECT COUNT(*)
FROM achievement_type;

-- Spocitame vysledny pocet
SELECT COUNT(*)
FROM account 
CROSS JOIN achievement_type;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D27">
                        <popis_dotazu>
                                <para>Vypiš všechny uživatele a ke každému všechny jeho získané achievementy. Zároveň vypiš všechny druhy achievementů, i když je nikdo ještě nezískal.
Seřaď podle ID uživatele a následně ID achievementu.</para>
                        </popis_dotazu>
                            <sql>SELECT  a.account_id,
        a.first_name,
        a.last_name,
        t.achievement_type_id,
        t.name,
        t.description
        
FROM account a

-- FULL (OUTER) JOIN vrati vsechny hodnoty z obou tabulek, a spoji ty, ktere spojit jdou
FULL JOIN achievement ach ON (a.account_id = ach.account_id)
FULL JOIN achievement_type t ON (ach.achievement_type_id = t.achievement_type_id)

ORDER BY a.account_id, t.achievement_type_id</sql>
                    </dotaz>
                    <dotaz dotaz_id="D28">
                        <popis_dotazu>
                                <para>Vyber 10 uživatelů (pouze žen), s největším počtem založených projektů, které mají alespoň 1 projekt. Spočítej jejich počet a vypiš ve sloupečku projects_count.

(wonky dotaz pro kategorii K)</para>
                        </popis_dotazu>
                            <sql>SELECT account.account_id, account.first_name, account.last_name, account.email, counted_accounts.count AS projects_count FROM
(
    -- Vyber account_id a ke kazdemu spocitej pocet projektu
    SELECT DISTINCT account_id, COUNT (account_id) FROM account_project
    JOIN project USING (project_id)
    GROUP BY account_id
    HAVING count(account_id) &gt;= 1
    
) AS counted_accounts
    
    
-- Spoj s tabulkou account, pro ziskani dalsich atributu
JOIN account USING (account_id)

-- Omezeni pouze na zeny (jmeno konci na &#039;á&#039;) - idealnejsi by bylo mit zaznam o pohlavi, a nebo napsat hezci where klauzuli ¯\_(ツ)_/¯
WHERE last_name LIKE &#039;%á&#039;

-- Serad podle poctu
ORDER BY counted_accounts.count DESC
    
LIMIT 10</sql>
                    </dotaz>
                    <dotaz dotaz_id="D29">
                        <popis_dotazu>
                                <para>Vyber takové uživatele, kteří momentálně pracují zároveň na novém a zároveň na probíhajícím projektu.</para>
                        </popis_dotazu>
                            <sql>SELECT account.account_id, account.first_name, account.last_name, account.email FROM account
JOIN account_project USING(account_id)
JOIN project USING(project_id)
WHERE state = &#039;new&#039;

INTERSECT

SELECT account.account_id, account.first_name, account.last_name, account.email FROM account
JOIN account_project USING(account_id)
JOIN project USING(project_id)
WHERE state = &#039;ongoing&#039;;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D30">
                        <popis_dotazu>
                                <para>Vyber uživatele a ke každému datum jeho posledního achievementu, pokud nějaký má.</para>
                        </popis_dotazu>
                            <sql>SELECT  account.account_id,
        account.first_name,
        account.last_name,
        account.email,
        (
            SELECT MAX(achieved_on_date) FROM achievement
            WHERE account.account_id = achievement.account_id
        ) AS last_achievement_date
        
FROM account</sql>
                    </dotaz>
                    <dotaz dotaz_id="D31">
                        <popis_dotazu>
                                <para>Uživatelům, kteří pracovali alespoň na 5 projektech dej achievement s ID 50, pokud ho ještě nemají.</para>
                        </popis_dotazu>
                            <sql>BEGIN;

-- Overeni poctu na zacatku
SELECT COUNT(*) FROM achievement ach
WHERE ach.achievement_type_id = 50;

INSERT INTO achievement (achievement_type_id, achieved_on_date, account_id)
(
    -- Pridej dalsi parametry k dotazu (ID 50 a datum)
    SELECT 50, CURRENT_DATE, account_id FROM
    (
        -- Vyber uzivatele, kteri maji narok na achievement
        SELECT account_id FROM account
        JOIN account_project USING (account_id)
        GROUP BY account_id
        HAVING COUNT(account_id) &gt;= 3
        
        EXCEPT
        
        -- Odeber ty, kteri jiz achievement maji (nelze ho pridat znovu)
        SELECT account_id FROM achievement
        WHERE achievement_type_id = 50
    ) AS accounts_to_give
);

-- Overeni poctu na konci
SELECT COUNT(*) FROM achievement ach
WHERE ach.achievement_type_id = 50;

ROLLBACK;</sql>
                    </dotaz>
                    <dotaz dotaz_id="D32">
                        <popis_dotazu>
                                <para>Protože společnost 11 zbankrotovala a již nebude podporovat žádné projekty, nastav všem jejím projektům stav na dokončený.</para>
                        </popis_dotazu>
                            <sql>BEGIN;

-- Overeni poctu na zacatku
SELECT COUNT(project_id) FROM project
WHERE organization_id = 11 AND state != &#039;complete&#039;;

-- Update vybranych zaznamu
UPDATE project
SET state = &#039;complete&#039;
WHERE project_id IN
(
    -- Vyber takove projekty, kterej nemaji stav complete
    SELECT project_id FROM project
    WHERE organization_id = 11 AND state != &#039;complete&#039;
);

-- Overeni poctu na konci (ocekavame 0)
SELECT COUNT(project_id) FROM project
WHERE organization_id = 11 AND state != &#039;complete&#039;;

ROLLBACK;</sql>
                    </dotaz>
            </dotazy>
            <pokryti_dotazu>
                        <radek>
                            <kategorie>A</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D3">D3</link>
                                    <link url="#D5">D5</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D10">D10</link>
                                    <link url="#D13">D13</link>
                                    <link url="#D14">D14</link>
                                    <link url="#D15">D15</link>
                                    <link url="#D16">D16</link>
                                    <link url="#D25">D25</link>
                                    <link url="#D27">D27</link>
                                    <link url="#D28">D28</link>
                                    <link url="#D29">D29</link>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>A - Pozitivní dotaz nad spojením alespoň dvou tabulek</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>AR</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D3">D3</link>
                                    <link url="#D5">D5</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D13">D13</link>
                                    <link url="#D14">D14</link>
                            </odkazy>
                            <kategorie_popis>A (RA) - Pozitivní dotaz nad spojením alespoň dvou tabulek</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>B</kategorie>
                            <odkazy>
                                    <link url="#D17">D17</link>
                                    <link url="#D18">D18</link>
                            </odkazy>
                            <kategorie_popis>B - Negativní dotaz nad spojením alespoň dvou tabulek</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>C</kategorie>
                            <odkazy>
                                    <link url="#D5">D5</link>
                            </odkazy>
                            <kategorie_popis>C - Vyber ty, kteří mají vztah POUZE k ...</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>D1</kategorie>
                            <odkazy>
                                    <link url="#D4">D4</link>
                            </odkazy>
                            <kategorie_popis>D1 - Vyber ty, kteří/které jsou ve vztahu se všemi - dotaz s univerzální kvantifikací</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>D2</kategorie>
                            <odkazy>
                                    <link url="#D12">D12</link>
                            </odkazy>
                            <kategorie_popis>D2 - Kontrola výsledku dotazu z kategorie D1</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F1</kategorie>
                            <odkazy>
                                    <link url="#D5">D5</link>
                                    <link url="#D14">D14</link>
                            </odkazy>
                            <kategorie_popis>F1 - JOIN ON</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F2</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D3">D3</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D10">D10</link>
                                    <link url="#D13">D13</link>
                                    <link url="#D14">D14</link>
                                    <link url="#D15">D15</link>
                                    <link url="#D16">D16</link>
                                    <link url="#D25">D25</link>
                                    <link url="#D28">D28</link>
                                    <link url="#D29">D29</link>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>F2 - NATURAL JOIN|JOIN USING</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F2R</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D3">D3</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D13">D13</link>
                                    <link url="#D14">D14</link>
                            </odkazy>
                            <kategorie_popis>F2 (RA) - NATURAL JOIN|JOIN USING</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F3</kategorie>
                            <odkazy>
                                    <link url="#D26">D26</link>
                            </odkazy>
                            <kategorie_popis>F3 - CROSS JOIN</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F4</kategorie>
                            <odkazy>
                                    <link url="#D25">D25</link>
                            </odkazy>
                            <kategorie_popis>F4 - LEFT|RIGHT OUTER JOIN</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>F5</kategorie>
                            <odkazy>
                                    <link url="#D27">D27</link>
                            </odkazy>
                            <kategorie_popis>F5 - FULL (OUTER) JOIN</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G1</kategorie>
                            <odkazy>
                                    <link url="#D4">D4</link>
                                    <link url="#D12">D12</link>
                                    <link url="#D17">D17</link>
                                    <link url="#D18">D18</link>
                                    <link url="#D19">D19</link>
                                    <link url="#D24">D24</link>
                                    <link url="#D32">D32</link>
                            </odkazy>
                            <kategorie_popis>G1 - Vnořený dotaz v klauzuli WHERE</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G1R</kategorie>
                            <odkazy>
                                    <link url="#D4">D4</link>
                                    <link url="#D12">D12</link>
                                    <link url="#D17">D17</link>
                                    <link url="#D18">D18</link>
                            </odkazy>
                            <kategorie_popis>G1 (RA) - Vnořený dotaz v klauzuli WHERE</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G2</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D12">D12</link>
                                    <link url="#D15">D15</link>
                                    <link url="#D16">D16</link>
                                    <link url="#D28">D28</link>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>G2 - Vnořený dotaz v klauzuli FROM</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G2R</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D8">D8</link>
                                    <link url="#D12">D12</link>
                            </odkazy>
                            <kategorie_popis>G2 (RA) - Vnořený dotaz v klauzuli FROM</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G3</kategorie>
                            <odkazy>
                                    <link url="#D30">D30</link>
                            </odkazy>
                            <kategorie_popis>G3 - Vnořený dotaz v klauzuli SELECT</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G4</kategorie>
                            <odkazy>
                                    <link url="#D17">D17</link>
                                    <link url="#D18">D18</link>
                                    <link url="#D24">D24</link>
                            </odkazy>
                            <kategorie_popis>G4 - Vztažený vnořený dotaz (EXISTS, NOT EXISTS)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>G4R</kategorie>
                            <odkazy>
                                    <link url="#D17">D17</link>
                                    <link url="#D18">D18</link>
                            </odkazy>
                            <kategorie_popis>G4 (RA) - Vztažený vnořený dotaz (EXISTS, NOT EXISTS)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>H1</kategorie>
                            <odkazy>
                                    <link url="#D20">D20</link>
                            </odkazy>
                            <kategorie_popis>H1 - Množinové sjednocení - UNION</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>H2</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D14">D14</link>
                                    <link url="#D20">D20</link>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>H2 - Množinový rozdíl - MINUS nebo EXCEPT</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>H2R</kategorie>
                            <odkazy>
                                    <link url="#D2">D2</link>
                                    <link url="#D14">D14</link>
                                    <link url="#D20">D20</link>
                            </odkazy>
                            <kategorie_popis>H2 (RA) - Množinový rozdíl - MINUS nebo EXCEPT</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>H3</kategorie>
                            <odkazy>
                                    <link url="#D29">D29</link>
                            </odkazy>
                            <kategorie_popis>H3 - Množinový průnik - INTERSECT</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>I1</kategorie>
                            <odkazy>
                                    <link url="#D4">D4</link>
                                    <link url="#D12">D12</link>
                                    <link url="#D15">D15</link>
                                    <link url="#D16">D16</link>
                                    <link url="#D19">D19</link>
                                    <link url="#D24">D24</link>
                                    <link url="#D25">D25</link>
                                    <link url="#D26">D26</link>
                                    <link url="#D28">D28</link>
                                    <link url="#D30">D30</link>
                                    <link url="#D31">D31</link>
                                    <link url="#D32">D32</link>
                            </odkazy>
                            <kategorie_popis>I1 - Agregační funkce (count|sum|min|max|avg)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>I1R</kategorie>
                            <odkazy>
                                    <link url="#D4">D4</link>
                                    <link url="#D12">D12</link>
                            </odkazy>
                            <kategorie_popis>I1 (RA) - Agregační funkce (count|sum|min|max|avg)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>I2</kategorie>
                            <odkazy>
                                    <link url="#D12">D12</link>
                                    <link url="#D15">D15</link>
                                    <link url="#D16">D16</link>
                                    <link url="#D25">D25</link>
                                    <link url="#D28">D28</link>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>I2 - Agregační funkce nad seskupenými řádky - GROUP BY (HAVING)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>I2R</kategorie>
                            <odkazy>
                                    <link url="#D12">D12</link>
                            </odkazy>
                            <kategorie_popis>I2 (RA) - Agregační funkce nad seskupenými řádky - GROUP BY (HAVING)</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>J</kategorie>
                            <odkazy>
                                    <link url="#D20">D20</link>
                            </odkazy>
                            <kategorie_popis>J - Stejný dotaz ve třech různých formulacích SQL</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>K</kategorie>
                            <odkazy>
                                    <link url="#D28">D28</link>
                            </odkazy>
                            <kategorie_popis>K - Všechny klauzule v 1 dotazu - SELECT FROM WHERE GROUP BY HAVING ORDER BY</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>L</kategorie>
                            <odkazy>
                                    <link url="#D23">D23</link>
                            </odkazy>
                            <kategorie_popis>L - VIEW</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>M</kategorie>
                            <odkazy>
                                    <link url="#D24">D24</link>
                            </odkazy>
                            <kategorie_popis>M - Dotaz nad pohledem</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>N</kategorie>
                            <odkazy>
                                    <link url="#D31">D31</link>
                            </odkazy>
                            <kategorie_popis>N - INSERT, který vloží do některé tabulky množinu řádků, které jsou vybrány dotazem z vybraných tabulek (příkaz INSERT, ve kterém je klauzule VALUES nahrazena vnořeným poddotazem.</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>O</kategorie>
                            <odkazy>
                                    <link url="#D32">D32</link>
                            </odkazy>
                            <kategorie_popis>O - UPDATE s vnořeným SELECT příkazem</kategorie_popis>
                        </radek>
                        <radek>
                            <kategorie>P</kategorie>
                            <odkazy>
                                    <link url="#D19">D19</link>
                                    <link url="#D24">D24</link>
                            </odkazy>
                            <kategorie_popis>P - DELETE s vnořeným SELECT příkazem</kategorie_popis>
                        </radek>
            </pokryti_dotazu>
        </queries>
        <scripts>
            <title>Scripts</title>
            <para>
                <link url="./create.sql">create.sql</link>
            </para>
            <para>
                <link url="./insert.sql">insert.sql</link>
            </para>
        </scripts>
        <conclussions>
            <title>Závěr</title>
                    <para>Na semestrální práci jsem strávil přiměřené množství času, zejména proto, že jsem již nějaké základní zkušenosti a povědomí o relačních databázích měl z uživatelského pohledu jako webového vývojáře. Novinkou pro mě bylo samotné tvoření databází, konceptuální modelování, relační algebra a komplexnější SQL dotazy, u kterých byl trochu oříšek naplnit všechny kategorie. Počet entit i rozsah práce byl z mého pohledu zvolený správně, nedělalo mi tudíž pak větší problém databázi naplnit daty, a zároveň jsem pokryl různé koncepty jako výlučné vazby, M:N vazby apod.</para>
                    <para></para>
                    <para>Naučil jsem se, jak správně ukládat různé typy dat jako např. SHA256 hashe [2] pro hesla (entita Account), MD5 hashe [5] pro soubory (Attachment), e-maily [4], alternativní přístup k enumu přes check [3] (Project.state), případně jak ověřovat pořadí datumů [6] (Project.creation_date a Project.deadline_date). Velmi mě zaujal nástroj Mockaroo [7] pro generování náhodných dat.</para>
                    <para></para>
                    <para>Prohlašuji, že jsem svou semestrální práci vypracoval samostatně. Všechny zdroje, ze kterých jsem čerpal, jsou uvedeny v části Zdroje.</para>
                    <para>Jan Černý</para>
        </conclussions>
        <references>
            <title>Zdroje</title>
                    <para>[1] Ukázková demo semestrálka Zoo ve skluzu [online]. Ing. Jiří Hunka, [cit. 14.04.2022]. Dostupné z: https://users.fit.cvut.cz/~hunkajir/dbs2/main.xml</para>
                    <para></para>
                    <para>[2] Ukázková demo semestrálka Datové úložiště [online]. Pepek Námořník, [cit. 14.04.2022]. Dostupné z: https://users.fit.cvut.cz/~valenta/BI-DBS/semestralka/ukazka/main.xml</para>
                    <para></para>
                    <para>[3] How long is the SHA256 hash in MySQL? [online]. tutorialspoint, [cit. 14.04.2022]. Dostupné z: https://www.tutorialspoint.com/how-long-is-the-sha256-hash-in-mysql</para>
                    <para></para>
                    <para>[4] Postgres ENUM data type or CHECK CONSTRAINT? [online]. Stack Overflow, [cit. 14.04.2022]. Dostupné z: https://stackoverflow.com/questions/10923213/postgres-enum-data-type-or-check-constraint</para>
                    <para></para>
                    <para>[5] SQL: What&#039;s the right column length for storing email addresses in a SQL Server database? [online]. Dr Greg Low, [cit. 14.04.2022]. Dostupné z: https://blog.greglow.com/2019/05/17/sql-column-length-storing-email-addresses-sqlserver-database/</para>
                    <para></para>
                    <para>[6] Can I use VARCHAR(32) for md5() values? [online]. Stack Overflow, [cit. 14.04.2022]. Dostupné z: https://stackoverflow.com/questions/14922208/can-i-use-varchar32-for-md5-values</para>
                    <para></para>
                    <para>[7] Check constraint for start/end date [online]. Stack Overflow, [cit. 14.04.2022]. Dostupné z: https://stackoverflow.com/questions/16637759/check-constraint-for-start-end-date</para>
                    <para></para>
                    <para>[8] Random Data Generator and API Mocking Tool [online]. Mockaroo, [cit. 14.04.2022]. Dostupné z: https://www.mockaroo.com/</para>
        </references>
    </content>
</sproject>
