Oskar Skibski, grupa nr 4, sala 2043

Bazy danych 2015/16

Laboratorium 3 (19.10.2015) - SQL / GRUPOWANIE

Dzisiaj nauczymy się trudnej sztuki grupowania wierszy oraz sprawdzimy jak działa rekurencja w ORACLu.

GROUP BY

W SQL istnieje możliwość grupowania wierszy. Przykładowo jeżeli chcemy przedstawić zbiorcze statystyki wierszy rozdzielając je podług zawartości jednej z kolumn możemy użyć konstrukcji GROUP BY. Grupować można także po wielu kolumnach. Sekcje GROUP BY umieszczamy po warunkach wybierających wiersze.

Po grupowaniu wierszy w sekcji SELECT nie możemy odnosić się do kolumn po których nie grupujemy w zwykły sposób, musimy zamiast tego używać funkcji agregujących. Jest to dość oczywiste, przykładowo kiedy pogrupujemy tabelę reprezentującą osoby po nazwisku to odwoływanie się do imienia nie ma sensu - imiona dla danego nazwiska mogą być przecież różne.

SELECT deptno, COUNT(*) ile FROM emp GROUP BY deptno ORDER BY deptno;
SELECT deptno, job, AVG(sal) zarobki FROM emp WHERE mgr IS NOT NULL GROUP BY deptno, job ORDER BY job;

Istnieje 5 funkcji agregujących:

Funkcji tych można używać także kiedy tabela nie jest grupowana, odnosić się będą wówczas do wszystkich wyselekcjonowanych wierszy.

O ile warunki na wiersze które grupujemy możemy umieścić w WHERE, to nie wiemy dotychczas gdzie umieścić warunki dotyczące cech grupy. Jak wybrać na przykład grupy które mają więcej niż 3 elementy? Z pomocą przychodzi nam kolejna konstrukcja SQL - HAVING.

SELECT COUNT(*), job, MIN(sal), MAX(sal) FROM emp GROUP BY job HAVING COUNT(*) > 3 ORDER BY job;

Warto zatrzymać się w tym miejscu na chwilę i zastanowić się nad tym jaka jest kolejność wykonywach operacji. Zapytanie:

Zadanie 1.

Korzystając tylko z danych tabeli emp:
  1. dla każdego stanowiska wyznacz liczbę pracowników i średnią płacę
  2. dla każdego departamentu z pracownikami wypisz ilu spośród nich ma prowizję (comm)
  3. znajdź maksymalną pensję na wszystkich stanowiskach na których pracuje co najmniej 3 pracowników zarabiających co najmniej 1000
  4. znajdź wszystkie miejsca w których rozpiętość pensji w tym samym departamencie na tym samym stanowisku przekracza 300
  5. policz średnie zarobki w departamencie w którym pracuje szef wszystkich szefów (czyli osoba która nie ma szefa)
  6. znajdź numer pracownika który ma podwładnych w różnych działach
  7. wypisz imiona oraz pensje wszystkich pracowników którzy nie mają zmiennika (osoby na tym samym stanowisku w tym samym departamencie) i posortuj ich według pensji malejąco

Rekurencja

No dobrze, umiemy wypisywać już całkiem dużo, ale jak na przykład wypisać wszystkich (niekoniecznie bezpośrednich) podwładnych danego pracownika? Z pomocą przychodzi nam konstrukcja CONNECT BY.

SELECT empno, ename, PRIOR ename AS mgr_ename, LEVEL 
FROM emp
START WITH mgr IS NULL
CONNECT BY PRIOR empno = mgr;

Po START WITH musimy umieścić warunek na wiersze od jakich budowa naszego drzewa ma się zacząć. W CONNECT BY definiujemy warunek złączenia dwóch wierszy. Aby odróżnić ich atrybuty używamy słówka PRIOR - atrybut poprzedzony tym słowem dotyczy wiersza "ojca", a nie poprzedzony - wiersza "syna". Tak jak w zapytaniach na wielu tabelach, może być on bardziej złożony niż jedna równość. Jeżeli chcemy przygotować ORACLE'a na pojawienie się cykli w naszym drzewie dodajemy słowo NOCYCLE - w przeciwnym wypadku po znalezieniu cyklu zgłosi wyjątek, obrazi się i nic nam nie wypisze.

W sekcji SELECT używać możemy także atrybutów wiersza "ojca", tak jak w CONNECT BY poprzedzamy je słówkiem PRIOR. Dodatkowo dochodzi nam parę specjalnych zmiennych/atrybutów. Najważniejszym jest LEVEL który informuje nas o tym na którym stopniu zagłębienia dany wiersz wystąpił (pierwszy poziom ma LEVEL 1). Innym przydatnym jest CONNECT_BY_ROOT, który pozwala nam sięgnąć do wiersza od którego nasza gałąź drzewa się zaczęła.

SELECT ename, CONNECT_BY_ROOT ename AS menago
FROM emp
START WITH job = 'MANAGER'
CONNECT BY PRIOR empno = mgr;

Dobrze uświadomić sobie, że warunek WHERE odnosi się do zbudowanego drzewa, dlatego także tam możemy na przykład odnosić się do zmiennej LEVEL czy PRIOR ename.

Zadanie 2.
  1. wypisz imiona wszystkich podwładnych KING'a (razem z nim) w taki sposób aby uzyskać strukturę drzewa:
    KING
      JONES
        SCOTT
          ADAMS
        FORD
          SMITH
          ...
    
  2. wypisz wszystkich podwładnych KING'a bez niego
  3. wypisz wszystkich podwładnych KING'a bez BLAKE'a i jego podwładnych
  4. wypisz wszystkich pracowników którzy mają "pod sobą" SALESMANa
  5. wypisz dla każdego pracownika sumę zarobków jego i jego podwładnych

Wbudowane funkcje

Obejrzyj format dat, funkcje na datach oraz funkcje na napisach.

Zadanie 3.
  1. czy w tabeli emp zawarta jest informacja o której godzinie zostali zatrudnieni wszyscy pracownicy?
  2. którzy pracownicy zostali zatrudnieni w 1982?
  3. jaki dzień tygodnia był 11 września 2001 roku?
  4. dla każdego pracownika wypisz kolumnę postaci "Józek (sprzedawca), WARSZAWA"

Oskar Skibski (oski@mimuw.edu.pl), Wydział Matematyki, Informatyki i Mechaniki