Autor Zpráva
holi
Profil
Zdravím,
omlouvám se za název tématu, ale můj problém nejde specifikovat jednou větou.

Mám seznam přiřazených učitelů k předmětům pro daného žáka. Každý žák má ale právo na jeden volitelný předmět z X volitelných předmětů v daném zaměření. Chci ze selectboxu vyřadit volitelné předměty pokud žák již má jeden z volitelných předmětů z jednoho zaměření přiřazen.

Přiřazení v databázi se provádí přes tabulku rozvrh kde je přiznak(bool) přiřazení pak id učitele, žáka a předmětu. Pomocí relací si vytáhnu z DB předměty, které se žáku mohou přiřadit(podle zaměření které žák má). Nyní potřebuji zjistit zda má žák již přiřazen volitelný předmět a pokud ano pak odstranit ostatní volitelné předměty z toho co jsem vytáhl v minulé větě(bacha! v zaměření jsou i povinné předměty). A zde jsem se zasekl. Prozatím to dělám v PHP přes dva dotazy a foreachem projíždím pole a odstranuji zbytek volitelných předmětů takto. Jenže to se mi nezdá jako správný způsob a chtěl bych to provést skrz SQL.

Takto teď vypadá funkce pro získání předmětů, kterou jsem popsal a ze které bych chtěl udělat jeden SQL dotaz:

<?php
        $available = $this->connection->query('SELECT [focuses].[focus], [subjects].[id], [subjects].[name], [subjects].[shortcut],
            [subjects].[level], [subjects].[class], [subjects].[hours], [subjects].[description], [subjects].[materials], [subjects].[optional]
            FROM [students]
            INNER JOIN [inclusions] ON [students].[id] = [inclusions].[student]
            INNER JOIN [focuses] ON [inclusions].[focus] = [focuses].[id]
            INNER JOIN [subjects] ON [focuses].[id] = [subjects].[focus]
                AND [inclusions].[level] = [subjects].[level]
                AND [inclusions].[class] = [subjects].[class]
            WHERE [students].[id] = %i
                AND [subjects].[id] NOT IN(SELECT [subject]
                    FROM [schedule]
                    WHERE [student] = [students].[id]
                        AND [assignment] = "1")
            GROUP BY [subjects].[id]', $id)->fetchAll();

       $control = $this->connection->query('SELECT [subject]
           FROM [schedule]
           JOIN [subjects] ON [schedule].[subject] = [subjects].[id]
           AND [student] = %i
           AND [assignment] = "1"
           AND [optional] = "1"', $id)->fetchAll();

       if(count($control)){

           foreach($available as $key => $subject){
               if($subject->optional)
                   unset ($available[$key]);

           }

       }

       return $available;
?>

BTW používám DIBI
tiso
Profil
Prečo to neurobíš naopak? Zistíš, či má priradený voliteľný predmet a podľa toho vyberieš buď všetky predmety, alebo len povinné.
holi
Profil
tiso:
Můžete dat nějaký příklad nemůžu si nějak představit jak to provést
Kajman
Profil
Zjistíte, zda dotaz z řádku 17 najde nějaký řádek. V tom případě přidáte do dotazu z řádku 2 podmínku např. do where, že optional není jedna nebo je null.
holi
Profil
Zřejmě jste me nepochopili. Já to všechno chci v jednom sql. Kdybych to chtěl na vice tak to zřejmě udělám i takhle, ale to pro me není řešení.
tiso
Profil
holi: čo je zlé na dvoch dotazoch do DB?
holi
Profil
Rychlost a vytížení serveru, kvůli tomu se vymysleli relační spojení tabulek.

EDIT:// Prostě se snažím nahnat každou milisekundu a byte v paměti

EDIT://Nehledě na to že funkci chci později použít na vypsání všech žáků, kteří nemají přiřazený nějaký předmět a v tomto případě by to znamenalo co žák to dotaz a že těch žáků bude :)
Alphard
Profil
Co třeba algoritmus v [#4] napsat do where pomocí poddotazu?
where (select count(*) ...) = 0 or (optional != 1 or optional is null)
Kajman
Profil
Snad by šlo i něco takového...

SELECT [focuses].[focus],
       [subjects].[id],
       [subjects].[name],
       [subjects].[shortcut],
       [subjects].[level],
       [subjects].[class],
       [subjects].[hours],
       [subjects].[description],
       [subjects].[materials],
       [subjects].[optional]
FROM   [students]
       INNER JOIN [inclusions]
               ON [students].[id] = [inclusions].[student]
       INNER JOIN [focuses]
               ON [inclusions].[focus] = [focuses].[id]
       INNER JOIN [subjects]
               ON [focuses].[id] = [subjects].[focus]
                  AND [inclusions].[level] = [subjects].[level]
                  AND [inclusions].[class] = [subjects].[class]
       LEFT JOIN [schedule]
              ON [students].[id] = [schedule].[student]
                 AND [subjects].[id] = [schedule].[subject]
                 AND [schedule].[assignment] = "1"
       LEFT JOIN [subjects] AS [subjects2]
              ON [subjects].[focus] = [subjects2].[focus]
                 AND [subjects].[level] = [subjects2].[level]
                 AND [subjects].[class] = [subjects2].[class]
                 AND [subjects].[optional] = "1"
                 AND [subjects2].[optional] = "1"
       LEFT JOIN [schedule] AS [schedule2]
              ON [students].[id] = [schedule2].[student]
                 AND [subjects2].[id] = [schedule2].[subject]
                 AND [schedule2].[assignment] = "1"
WHERE  [students].[id] = %i
       AND [schedule].[subject] IS NULL
       AND [schedule2].[subject] IS NULL
GROUP  BY [subjects].[id]  


Ale tipuji, že to nebude přínos ani v rychlosti ani v čitelnosti kódu oproti řešení v [#2].
holi
Profil
Tak jsem to vyřešil, tady je funkční skript.

query('SELECT [focuses].[focus], [subjects].[id], [subjects].[name], [subjects].[shortcut],
            [subjects].[level], [subjects].[class], [subjects].[hours], [subjects].[description], [subjects].[materials], [subjects].[optional]
            FROM [students]
            INNER JOIN [inclusions] ON [students].[id] = [inclusions].[student]
            INNER JOIN [focuses] ON [inclusions].[focus] = [focuses].[id]
            INNER JOIN [subjects] ON [focuses].[id] = [subjects].[focus]
                AND [inclusions].[level] = [subjects].[level]
                AND [inclusions].[class] = [subjects].[class]
            WHERE  [students].[id] = %i',$id,'
                AND [subjects].[id] NOT IN(SELECT [subject]
                    FROM [schedule]
                    WHERE [student] = [students].[id]
                        AND [assignment] = "1")
                AND ((SELECT COUNT([sch].[id])
                    FROM [schedule] AS [sch]
                    JOIN [subjects] AS [s] ON [sch].[subject] = [s].[id]
                    WHERE [sch].[student] = [students].[id]
                        AND [sch].[assignment] = "1"
                        AND [s].[optional] = "1"
                        AND [inclusions].[class] = [s].[class]
                        AND [inclusions].[level] = [s].[level]
                        AND [inclusions].[focus] = [s].[focus]) = 0 OR subjects.optional = 0)
            GROUP BY [subjects].[id] ORDER BY [focus]')

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

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

0