SELECT WHERESQL służy do ograniczania wyników zapytania. Wykorzystanie SELECT WHERE jest w bazach danych jest niezwykle często wykorzystywane ponieważ pozwala sterować które rekordy i pod jakimi warunkami mogą zostać zwrócone w wyniku zapytania. W poniższym kursie dotyczącym WHERE:

  • Przygotuję bazę
  • Opiszę podstawową składnię SELECT WHERE w tym
    • Przedstawię porównania =
    • Poznasz co oznacza błąd: ORA-01722: niepoprawna liczba
    • Pokażę zaprzeczenie porównania czyli <>
    • Pokażę jak wybrać większe i mniejsze rekordy przy użyciu znaków > i <
    • Przedstawię działanie operatora WHERE BETWEEN
    • Pokażę, jak łączyć warunki przy pomocy operatorów logicznych AND i OR
  • Podsumuję cały kurs
  • Przedstawię ćwiczenie + jego rozwiązanie

Ten kurs jest częścią cyklu Kurs SQL

Zapisz się na autorskie Szkolenie SQL

Przygotowanie bazy danych

We wszystkich kursach korzystam z tej samej bazy danych którą w trakcie kursów sukcesywnie rozszerzam. Schemat testowej bazy danych został opracowany w kursie dotyczącym normalizacji baz danych. Jeżeli już masz przygotowaną bazę danych jak poniżej pomiń ten krok.

oracle create table

Aby utworzyć powyższy schemat bazy danych należy wykonać skrypt z ćwiczenia z kursu SQL DROP | CREATE TABLE (Dodawanie i usuwanie tabel):

CREATE TABLE CENNIK (
    ROZMIAR VARCHAR2(3 CHAR)
  , CENA    NUMBER
  
  , CONSTRAINT CENNIK_PK PRIMARY KEY (ROZMIAR) 
);

CREATE TABLE MENU (
    ID      NUMBER GENERATED ALWAYS AS IDENTITY
  , NAZWA   VARCHAR2(20 CHAR)
  , ROZMIAR VARCHAR2(3 CHAR)
  
  , CONSTRAINT MENU_PK PRIMARY KEY (ID)
  , CONSTRAINT MENU_CENNIK_FK FOREIGN KEY (ROZMIAR) REFERENCES CENNIK(ROZMIAR)
);

CREATE TABLE KLIENT (
    ID       NUMBER GENERATED ALWAYS AS IDENTITY
  , IMIE     VARCHAR2(20 CHAR)
  , NAZWISKO VARCHAR2(20 CHAR)
  
  , CONSTRAINT KLIENT_PK PRIMARY KEY (ID)
);

CREATE TABLE ADRES (
    ID_ADRESU     NUMBER GENERATED ALWAYS AS IDENTITY
  , ULICA         VARCHAR2(20 CHAR)
  , NR_BLOKU      VARCHAR2(10 CHAR)
  , NR_MIESZKANIA VARCHAR2(10 CHAR)
  , MIASTO        VARCHAR2(20 CHAR)
  
  , CONSTRAINT ADRES_PK PRIMARY KEY (ID_ADRESU)
);

CREATE TABLE ZAMOWIENIA (
    ID_PIZZA        NUMBER
  , ID_KLIENTA      NUMBER
  , ID_ADRESU       NUMBER
  , DATA_ZAMOWIENIA DATE
  
  , CONSTRAINT ZAM_PIZZA_FK FOREIGN KEY (ID_PIZZA) REFERENCES MENU(ID)
  , CONSTRAINT ZAM_KLIENT_FK FOREIGN KEY (ID_KLIENTA) REFERENCES KLIENT(ID)
  , CONSTRAINT ZAM_ADRES_FK FOREIGN KEY (ID_ADRESU) REFERENCES ADRES(ID_ADRESU)
);

Natomiast do wypełnienia danych posłuży skrypt z ćwiczenia z kursu SQL INSERT | DELTE | UPDATE (Modyfikacja danych tabel):

INSERT INTO CENNIK (ROZMIAR, CENA) VALUES ('L', 15);
INSERT INTO CENNIK (ROZMIAR, CENA) VALUES ('XL', 20);
INSERT INTO CENNIK (ROZMIAR, CENA) VALUES ('XXL', 25);

INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Margherita', 'XXL');
INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Margherita', 'L');
INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Pepperonia', 'L');
INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Hawajska', 'L');
INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Margherita', 'XL');
INSERT INTO MENU (NAZWA, ROZMIAR) VALUES ('Wiejska', 'XXL');

INSERT INTO KLIENT (IMIE, NAZWISKO) VALUES ('Jan', 'Kowalski');
INSERT INTO KLIENT (IMIE, NAZWISKO) VALUES ('Piotr', 'Nowak');
INSERT INTO KLIENT (IMIE, NAZWISKO) VALUES ('Anna', 'Zaradna');
INSERT INTO KLIENT (IMIE, NAZWISKO) VALUES ('Kamila', 'Zaradna');

INSERT INTO ADRES (ULICA, NR_BLOKU, NR_MIESZKANIA, MIASTO) VALUES ('Hery', 5, null, 'Warszawa');
INSERT INTO ADRES (ULICA, NR_BLOKU, MIASTO) VALUES ('Domaniewska', 2, 'Poznań');
INSERT INTO ADRES (ULICA, MIASTO) VALUES ('JP2', 'Warszawa');
INSERT INTO ADRES (ULICA, MIASTO) VALUES ('JP2', 'Wrocław');

INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, ID_ADRESU, DATA_ZAMOWIENIA) VALUES (1, 1, 1, '2019-01-01');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, ID_ADRESU, DATA_ZAMOWIENIA) VALUES (2, 2, 2, '2019-01-02');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, ID_ADRESU, DATA_ZAMOWIENIA) VALUES (3, 2, 2, '2019-01-02');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, DATA_ZAMOWIENIA) VALUES (4, 3, '2019-01-03');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, DATA_ZAMOWIENIA) VALUES (5, 3, '2019-01-03');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, DATA_ZAMOWIENIA) VALUES (6, 3, '2019-01-03');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, ID_ADRESU, DATA_ZAMOWIENIA) VALUES (2, 3, 3, '2019-01-05');
INSERT INTO ZAMOWIENIA (ID_PIZZA, ID_KLIENTA, ID_ADRESU, DATA_ZAMOWIENIA) VALUES (3, 4, 4, '2019-01-06');
COMMIT;

Przed rozpoczęciem tego kursu warto zapoznać się z kursem dotyczącym pobierania danych z tabeli przy pomocy klauzuli SELECT FROM

Składnia SQL SELECT WHERE

Znając już strukturę bazy danych i przechowywanych w niej danych możemy opracować zapytanie które pozwoli wyświetlić tylko część rekordów z tabeli bazy danych. Podstawowa struktura zapytania SELECT WHERE wygląda następująco:

SELECT
    kolumna_1
  , kolumna_2
    ...
  , kolumna_n
FROM
    nazwa_tabeli
WHERE warunek_1
operator_logiczny warunek_2
...
operator_logiczny warunek_n;

Struktura polecenia jest rozszerzeniem SLECET FROM. Klauzula WHERE służy do ograniczania wyników zapytania. Po klauzuli WHERE należy podać pierwszy warunek a następnie operator logiczny i kolejny warunek. Operatorów logicznych i warunków może być nieskończenie wiele.

SELECT WHERE =

Pierwszym ograniczeniem które poznamy jest równoważność oznaczone znakiem “=”. Po jednej stronie podajemy kolumnę a po drugiej wartość jaką powinna przyjąć kolumna aby rekord został zwrócony do wyniku zapytania.

Dla przykładu postarajmy się wybrać wszystkie osoby o imieniu “Jan” z tabeli KLIENT. Przykładowe zapytanie może wyglądać jak poniżej:

SELECT
    ID
  , IMIE
  , NAZWISKO
FROM
    KLIENT
WHERE
  IMIE = 'Jan';

oraz wynik:

Tabela KLIENT posiada 4 rekordy jednak tylko jeden gdzie kolumna IMIE ma wartość ‘Jan’.

Aby poprawnie przyrównać wartości kolumn należy zwrócić uwagę na jej typ, dlatego też porównując do kolumn typu:

  • CHAR, VARCHAR2 porównujemy wartości w cudzysłowach ” np. =’Jan’. Wartość przyrównywana jest czuła na wielkość liter dlatego ‘JAN’ i ‘Jan’ to inne wartości.
  • NUMBER przyrównujemy do wartości numerycznej bez użycia cudzysłowów np. = 10
  • Dla kolumn typu DATE powinniśmy porównać do wartości datowej np. = sysdate

ORA-01722: niepoprawna liczba

Co w takim razie gdy podamy zły typ danych w porównaniu jak w poniżej:

SELECT
    ID
  , IMIE
  , NAZWISKO
FROM
    KLIENT
WHERE
  IMIE = 1;

Jako, że kolumna IMIE jest typu varchar2 a porównujemy ją do wartości liczbowej 1 to baza danych zwróci nam błąd:

ORA-01722: niepoprawna liczba
00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.

Błąd ten oznacza, że przyrównujemy zły typ danych do kolumny.

Uwaga: Baza danych potrafi w niektórych przypadkach niejawnie przekonwertować liczbę na znaki dlatego dla przyrównania =’1′ możemy otrzymać ten sam wynik co dla =1 zgodnie z poniższym przykładem:

Pomimo, że kolumna ID jest typu number a ‘1’ jest typu znakowego to baza potrafiła przekonwertować znak ‘1’ na liczbę 1.

SELECT WHERE <>

Kolejnym ograniczeniem jest “różne niż” czyli znak <>. W wielu językach programowania porównanie tego typu oznaczone jest znakami (wykrzyknik równa się) != ale w bazie danych oracle jest to znacznik <>. Użycie tego porównania zwraca nam rekord do wyniku zapytania w sytuacji gdy lewa i prawa porównania stroną są różne.

Dla przykładu wyciągnijmy wszyskich klientów którzy nie mają na imię ‘Jan’, zapytanie może wyglądać jak poniżej

SELECT
    ID
  , IMIE
  , NAZWISKO
FROM
    KLIENT
WHERE
  IMIE <> 'Jan';

oraz wynik zapytania

Powyższe zapytanie zwróciło nam wszystkie rekordy w których kolumna IMIE przyjmuje wartości inne niż ‘Jan’

SELECT WHERE > <

Kolejnym ograniczeniem będą znaki większości > i mniejszości <. Służą one do porównywania wartości numerycznych lub dat. Porównania te nie są włączne ( ang. inclusive) tzn. 20 > 20 nie zwróci rekordu do wyniku zapytania. Dlatego aby zmienić porównanie na zawierające skrajną wartość należy dodać znak = np. >= lub <= w tym przypadku 20 >= 20 zwróci rekord.

Napiszmy w takim razie zapytanie które zwróci z tabeli CENNIK takie rekordy gdzie kolumna CENA ma wartość większą 20. Przykładowe zapytanie może wyglądać jak poniżej:

SELECT
    *
FROM CENNIK
WHERE CENA > 20;

oraz wynik:

W tabeli CENNIK mamy łącznie 3 rekordy w tym tylko jeden dla który w kolumnie CENA przyjmują wartość większą niż 20.

Zobaczmy jeszcze jak może wyglądać zapytanie gdybyśmy chcieli zwrócić rekordy dla których cena jest większa lub równa 20:

SELECT
    *
FROM CENNIK
WHERE CENA > 20;

oraz wynik:

SELECT WHERE BETWEEN

Połączeniem ograniczenia > i < jest ograniczenie BETWEEN wartość_1 AND wartość_2 które mówi, że kolumna jest z przedziału dwóch liczb.

Dla przykładu poszukajmy więc w cenniku wartości CENA pomiędzy 20 a 30. Zapytanie może wyglądać jak poniżej:

SELECT
  *
FROM CENNIK
WHERE CENA BETWEEN 20 AND 30;

oraz wynik:

Jak widzimy klauzula BETWEEN również nie jest włączna. Klauzula BETWEEN nie występuje w wersji włacznej (ang. inclusive), aby spełnić warunek z włączeniem wartości brzegowych należy połączyć dwa warunku >= oraz <= jednak o łączeniu warunków w poniższym rozdziale o operatorach logicznych.

Łączenie warunków przy pomocy operatorów logicznych AND i OR

Wszystkie powyżej przedstawione sposoby ograniczania rekordów można łączyć ze sobą przy pomocy operatorów logicznych AND i OR. Nim jednak przejdę do przykładów krótkie przypomnienie które co zwraca AND i OR dla poszczególnych wartości logicznych:

ABA AND BA OR B
truetruetruetrue
truefalsefalsetrue
falsetruefalsetrue
falsefalsefalsefalse

Łączenie warunków ograniczających rekordy w zapytaniu polega na łączeniu operatorami logicznymi AND i OR warunków. Jeżeli warunek jest spełniony zwraca ono wartość true jeżeli natomiast nie jest spełniony to zwraca wartość false. Dzięki temu możemy łączyć warunki.

Uwaga: Jakiekolwiek porównanie do wartości NULL zwraca wartość NULL co nie jest ani true ani false. O logice trójargumentowej i NULL w bazie Oracle opiszę w innym kursie. Narazie pomijam przypadki z nullem.

Spróbujmy więc znaleźć w tabeli KLIENT osoby które mają na imię ‘Jan’ lub nazwisko ‘Zaradna’. Warunek lub oznacza, że należy wykorzystać operator OR. Zobaczmy jak może wyglądać przykładowe zapytanie:

SELECT
    ID
  , IMIE
  , NAZWISKO
FROM
    KLIENT
WHERE
  IMIE = 'Jan'
  OR NAZWISKO = 'Zaradna';

oraz wynik:

Powyższe zapytanie zwróciło nam 3 rekordy ponieważ każdy z nich spełnia powyższy warunek. Jedynym rekordem nie spełniającym warunków z zapytania jest Piotr Nowak ponieważ ani jego imie ani nazwisko nie zgadza się z warunkami.

Zapytanie zwracające Piotra Nowaka możemy skonstruować przy pomocy operatora AND:

SELECT
    ID
  , IMIE
  , NAZWISKO
FROM
    KLIENT
WHERE
  IMIE = 'Piotr'
  AND NAZWISKO = 'Nowak';

oraz wynik:

Jak widzimy jedynie jeden rekord spełnia jednocześnie warunek IMIE = ‘Piotr’ i NAZWISKO = ‘Nowak’

Znając już działanie tych operatorów napiszmy zapytanie które zwróci nam z tabeli CENNIK wartości od 20 do 40 włącznie po obu stronach. Przykładowe zapytanie może wyglądać jak poniżej:

SELECT
    *
FROM CENNIK
WHERE CENA >= 20
  AND CENA <= 40;

oraz wynik:

W powyższym wyniku widzimy wszystkie rekordy z tabeli CENNIK gdzie cena zaczyna się od 20 włącznie i jest mniejsza niż 40 również włącznie.

Podsumowanie

Z powyższego kursu SELECT WHERE nauczyłeś się, jak ograniczać wyniki zapytania a w szczególnośći:

  • Ograniczeniu kolumny do konkretnej wartości służy operator “=”
  • Wyszukując wartości “różnych od” służy operator “<>”
  • Do wyszukiwania większych i mniejszych wartości służą operatory “>” i “<“
  • Klauzula WHERE BETWEEN pozwala znaleźć rekordy z zakresu dwóch wartośći
  • W ograniczeniach należy zwracać uwagę na typ danych i tak dla:
    • Kolumn tekstowych wartości wpisujemy w pojedynczym cudzysłowiu np. = ‘Jan’
    • Kolumn numerycznych podajemy wartośc numeryczną np. = 10
  • Gdy w porównaniu podamy zły typ baza danych zwróci błąd: ORA-01722: niepoprawna liczba
  • Do łączenia warunków służą operatory:
    • AND – zwraca rekordy tylko gdy oba warunki są spełnione
    • OR – zwraca rekord gdy przynajmniej jeden warunek jest spełniony

Ćwiczenie

  1. Z tabeli MENU znaleźć wszystkie pizze w rozmiarze “L”
  2. Znaleźć w tabeli ADRES w mieście Warszawa i ulicy Hery
  3. Znaleźć w tabeli CENNIK z przedziału od 0 do 20 bez wartości granicznych.

Odpowiedzi:

  1. Z tabeli MENU znaleźć wszystkie pizze w rozmiarze “L”
SELECT
  *
FROM MENU
WHERE ROZMIAR = 'L';

2. Znaleźć w tabeli ADRES w mieście Warszawa i ulicy Hery

SELECT
  *
FROM ADRES
WHERE MIASTO = 'Warszawa'
  AND ULICA = 'Hery';

3. Znaleźć w tabeli CENNIK z przedziału od 0 do 20 bez wartości granicznych.

SELECT
  *
FROM CENNIK
WHERE CENA BETWEEN 0 AND 20;

lub

SELECT
  *
FROM CENNIK
WHERE CENA > 0
  AND CENA < 20;

  • Jeżeli chcesz znaleźć więcej kursów dla średniozaawansowanych oraz poznać zasady optymalizacji zapytań zapoznaj się z pozostałymi kursami, sprawdź: Kurs Oracle SQL
  • Jeżeli chcesz poznać podstawy baz danych i kurs dla początkujących w SQL odwiedź Kurs SQL

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *