Krok 1. Najważniejsze jest obliczenie średniej z wybranych ocen.
policzy średnią ze wszystkiego jak leci.
Krok 2.
weźmie do średniej tylko te krotki (wiersze, rekordy -- jak je zwiesz), które spełniają warunek ... Taki warunek musi być funkcją zdaniową (tzn. wyrażeniem logicznym, któremu da się przyporządkować wartość Prawda, Fałsz albo NULL po podstawieniu konkretnych wartości).
Na przykład (brzydko):
Kod: Zaznacz cały
select avg(Ocena) from tbOceny where PrzedmiotID = 22 and OddzialID = 3455
Brzydkość wiąże się z tym, że opis realnego świata korzysta z pojęć takich, jak: dostatecznie, 3.0, matematyka, 1B, Jurek Nowak, ale nie ma pojęcia o wartościach kluczy identyfikujących i wiążących dane w bazie. Takie pytanie korzysta z wewnętrznej organizacji konkretnej bazy.
Nie da się spytać tabeli Oceny ani o klasę 1B, ani o matematykę. Jeżeli przejrzymy zawartość, to widzimy, że takich pojęć -- ba: miejsca na nie! -- tam po prostu nie ma. One są w innych tabelach.
Krok 3.
Dlatego potrzebujemy łączyć tabele ze sobą. Istnieje kilka składni pozwalających to uzyskać. Niektóre jawnie korzystają z operacji tabela1 JOIN tabela2 ON warunek albo tabela1 JOIN tabela2 USING(nazwa_kolumny).
Wynikiem takiego złączenia byłaby tabela Oceny poszerzona o kolumny z tabeli Oddziały (wartości odpowiadające klasie, w której dokonano oceny) oraz o kolumny z tabeli Przedmioty (z wartościami odpowiadającymi przedmiotowi, z którego wystawiono daną ocenę). To jest bardzo jasna intuicyjnie operacja, i warto ją przeprowadzić na krótkich tabelach samemu, ręcznie -- bez użycia komputera, żeby zrozumieć jak to działa.
W Twojej wersji jest inaczej: wykonujesz tzw pełnie połączenie (FULL JOIN) przerzucając warunek dopasowania wierszy na etap warunku filtrującego (wyboru): ... FROM tabela1, tabela2 WHERE warunek.
Wynikiem takiego złączenia jest olbrzymia tabela zawierająca wszystkie możliwe kombinacje wierszy z tabel Przedmioty, Oceny i Oddziały, z których następnie wybieramy (WHERE) te sensowne i spełniające nasze potrzeby). Wynik będzie ten sam co poprzednio.
Prawdziwy system nie będzie tworzył tej ogromnej śmieciowej tabeli, ręcznie też nie chcielibyśmy jej pisać.
W Twojej konstrukcji
Kod: Zaznacz cały
SELECT "tbOddziały"."Oznaczenie", "tbPrzedmioty"."Nazwa przedmiotu", AVG( "tbOceny"."Ocena" ) AS "Średnia ocen" FROM "tbOceny", "tbPrzedmioty", "tbOddziały" WHERE "tbOceny"."PrzedmiotID" = "tbPrzedmioty"."IDPrzedmiotu" AND "tbOddziały"."Oznaczenie" = '1B' AND "tbPrzedmioty"."Nazwa przedmiotu" = 'matematyka'
masz warunek złożony (koniunkcja, czyli AND), w którym fraza pierwsza opisuje sensowne złączenie ocen i przedmiotów, fraza druga wybiera oddział, fraza trzecia wybiera przedmiot. Ale brakuje frazy decydującej o dopasowaniu ocen do oddziału. Nie znając struktury tabel nie da się jej dopisać bezbłędnie.
Krok 4.
Mamy dostać nazwę przedmiotu i średnią.
Kod: Zaznacz cały
SELECT nazwa as "Przedmiot", AVG(..) as "Średnia" FROM ...
Wariant 1, prostszy: nazwa to po prostu stała tekstowa 'matematyka'. Wada jest taka, że dana wejściowa pojawia się w zapytaniu dwukrotnie. Kto to przegapi i zmodyfikuje pytanie, dostanie fałszywą odpowiedź.
Wariant 2: grupować odpowiedzi wg przedmiotów, ale wziąć tylko grupę dot. wartości matematyka. Wbrew pozorom pozostałe grupy nie będą w ogóle konstruowane w bazie. To wymaga znajomości klauzuli grupuj (GROUP BY) oraz wyboru grup (HAVING). Jest więc bardziej zaawansowany, ale eliminuje możliwość głupich pomyłek przy przeredagowaniu pytania.
Krok 5.
Graficzny asystent tworzenia zapytań. Moim zdaniem on ogranicza, nie pomaga. Przynajmniej do jakiegoś tam stopnia złożoności problemu. No ale zawsze można podejrzeć w widoku SQL, co się zbudowało, i to poprawiać.
Są lepsze i gorsze asystenty zapytań. Niektóre porażają kreatywnością; inne są takie sobie. Spodobały mi się: DbWrench oraz DbVisualizer -- oba w wersjach komercyjnych, które można sobie na pewien czas ściągnąć do darmowego testowania. Asystent wbudowany w OO Base jest dość toporny, niestety.