Ściągawka SQL (PostgreSQL)

Instrukcje, których potrzebujesz najczęściej, po jednym przykładzie każda. Przykłady działają na bazie ćwiczeniowej piekarni i używają składni PostgreSQL. Inne bazy różnią się drobnymi szczegółami, które są opisane tam, gdzie mają znaczenie.

Czytaj i filtruj

SELECT wybiera kolumny, FROM wskazuje tabelę, WHERE zachowuje pasujące wiersze, ORDER BY sortuje, LIMIT ogranicza wynik. Tekst wpisuj w pojedynczych apostrofach.

Komentarze są ignorowane: `--` do końca wiersza albo `/* ... */` w wielu wierszach. Używaj ich, żeby wyjaśnić zapytanie, nie zamiast jasnego polecenia.

SELECT name, unit_price
FROM products
WHERE category = 'pastry' AND unit_price < 3
ORDER BY unit_price DESC
LIMIT 5;

Wynik: Ciastka i wypieki poniżej 3.00, od najdroższego.

Wzorce, listy, zakresy i NULL

LIKE dopasowuje wzorce (% to dowolny tekst, _ to jeden znak; ILIKE ignoruje wielkość liter). IN sprawdza listę, BETWEEN sprawdza zakres z obiema granicami, IS NULL znajduje brakujące wartości.

SELECT first_name, loyalty_tier
FROM customers
WHERE first_name LIKE 'A%' OR loyalty_tier IS NULL
ORDER BY first_name;

Wynik: Klienci, których imię zaczyna się na A, albo którzy nie mają poziomu lojalności.

Podsumuj za pomocą GROUP BY

COUNT, SUM, AVG, MIN i MAX zamieniają wiersze w jedną wartość na grupę. WHERE filtruje wiersze przed grupowaniem, HAVING filtruje grupy.

SELECT channel, COUNT(*) AS orders
FROM orders
GROUP BY channel
HAVING COUNT(*) > 5
ORDER BY channel;

Wynik: Tylko kanał online, z 7 zamówieniami.

Łącz tabele

INNER JOIN zachowuje dopasowania, LEFT JOIN zachowuje każdy wiersz lewej tabeli. Nadawaj tabelom krótkie aliasy i zawsze łącz po kluczu.

SELECT p.name, SUM(oi.quantity) AS units
FROM products AS p
JOIN order_items AS oi ON oi.product_id = p.product_id
GROUP BY p.name
ORDER BY units DESC, p.name
LIMIT 3;

Wynik: Trzy najlepiej sprzedające się produkty.

CASE: if/else w SQL

CASE zwraca wartość pierwszego spełnionego warunku, podobnie jak IFS w Excelu. Bez ELSE zwraca NULL.

SELECT name,
       CASE WHEN unit_price < 3 THEN 'budget' WHEN unit_price <= 4 THEN 'standard' ELSE 'premium' END AS band
FROM products
ORDER BY product_id;

Wynik: Każdy produkt oznaczony jako budget, standard lub premium.

Podzapytania i WITH

Podzapytanie to zapytanie wewnątrz innego zapytania. WITH nadaje mu nazwę, dzięki czemu główne zapytanie czyta się jak historię.

ANY i ALL porównują wartość z całym podzapytaniem: `> ALL` znaczy większe niż każda wartość, `> ANY` większe niż przynajmniej jedna. `= ANY` to to samo co IN.

WITH spend AS (
  SELECT o.customer_id, SUM(oi.quantity * p.unit_price) AS total
  FROM orders AS o
  JOIN order_items AS oi ON oi.order_id = o.order_id
  JOIN products AS p ON p.product_id = oi.product_id
  GROUP BY o.customer_id
)
SELECT customer_id, total FROM spend WHERE total > 30 ORDER BY total DESC;

Wynik: Klient 1 (Lopez) z kwotą 37.10 i klient 3 (Dubois) z kwotą 36.00.

Funkcje okna

OVER dodaje obliczenie w poprzek wierszy bez ich zwijania: rangi, sumy narastające oraz LAG i LEAD dla poprzedniego i następnego wiersza.

SELECT order_id, order_date,
       RANK() OVER (ORDER BY order_date) AS day_rank,
       LAG(order_date) OVER (ORDER BY order_id) AS prev_date
FROM orders
ORDER BY order_id;

Wynik: Każde zamówienie z jego rangą według daty i datą poprzedniego zamówienia.

Zmieniaj dane

INSERT dodaje wiersze, UPDATE je zmienia, DELETE usuwa. Zawsze dodawaj WHERE w UPDATE i DELETE i najpierw uruchom to jako SELECT, żeby zobaczyć, czego dotyczy. Ryzykowne zmiany opakuj w BEGIN i ROLLBACK.

`INSERT INTO t SELECT ...` kopiuje wiersze do tabeli, która już istnieje. `CREATE TABLE t AS SELECT ...` tworzy nową tabelę z zapytania. Klucze całkowite mogą wypełniać się same przez `GENERATED ALWAYS AS IDENTITY` (MySQL: AUTO_INCREMENT; SQL Server: IDENTITY).

UPDATE products
SET unit_price = unit_price + 0.10
WHERE category = 'drinks'
RETURNING name, unit_price;

Wynik: Dwa napoje z ich nowymi cenami.

Częste pytania

W jakiej kolejności SQL wykonuje zapytanie?
Najpierw FROM i JOIN, potem WHERE, GROUP BY, HAVING, SELECT, ORDER BY i na końcu LIMIT. Dlatego WHERE nie może użyć aliasu kolumny z SELECT, ale ORDER BY może.
Czy SQL rozróżnia wielkość liter?
Słowa kluczowe oraz nazwy tabel i kolumn nie (PostgreSQL zamienia nazwy bez cudzysłowów na małe litery). Wartości tekstowe już tak: 'Paris' i 'paris' się różnią, chyba że użyjesz ILIKE lub LOWER().
Czy to działa w MySQL, SQL Server lub SQLite?
Rdzeń (SELECT, WHERE, GROUP BY, JOIN, CASE) tak. Różnice dotyczą LIMIT (w SQL Server to TOP), łączenia tekstu, funkcji dat i RETURNING. Szczegóły sprawdź w dokumentacji swojej bazy.
Jak napisać komentarz w SQL?
Pojedynczy wiersz zaczyna się od -- i trwa do końca tego wiersza. Komentarz blokowy zaczyna się od /* i kończy na */. Baza ignoruje oba. Microsoft Access nie obsługuje komentarzy.

Ćwicz to