UNION w SQL - składnia, UNION ALL i różnice względem JOIN

Konstanty Jankowski • 30 września 2026
Wizualizacja pokazuje, jak `sql union` łączy dane z dwóch tabel, usuwając duplikaty (A,B,C,D,E,F).

Spis treści

Łączenie danych z kilku tabel lub zapytań często wygląda podobnie do zwykłego łączenia tabel, ale działa według zupełnie innej zasady. Operator UNION w SQL, znany też jako sql union, pozwala zestawić wyniki kilku instrukcji SELECT w jeden wspólny wynik. Pokażę, jak działa, czym różni się od UNION ALL, kiedy lepiej użyć JOIN oraz jak unikać błędów związanych z kolumnami, duplikatami i sortowaniem.

Najważniejsze zasady łączenia wyników w SQL

  • UNION łączy wyniki kilku zapytań i usuwa powtarzające się wiersze.
  • UNION ALL zachowuje duplikaty i zwykle działa szybciej.
  • Każde zapytanie musi zwracać taką samą liczbę kolumn w tej samej kolejności.
  • Odpowiadające sobie kolumny muszą mieć zgodne lub konwertowalne typy danych.
  • ORDER BY dla całego wyniku umieszcza się zazwyczaj na końcu konstrukcji.

Wizualizacja porównuje `SQL UNION` i `UNION ALL`. `UNION` łączy tabele A i B, usuwając duplikaty. `UNION ALL` zachowuje wszystkie wiersze, w tym duplikaty.

Jak działa operator UNION

UNION traktuje wyniki zapytań jak dwa zbiory danych i dokłada wiersze jeden pod drugim. Nie łączy kolumn w poziomie, lecz tworzy jeden większy zestaw rekordów z kilku instrukcji SELECT.

SELECT imie, email
FROM klienci
WHERE miasto = 'Kraków'

UNION

SELECT imie, email
FROM klienci
WHERE miasto = 'Gdańsk';

Wynik zawiera klientów z obu miast. Jeżeli identyczny wiersz pojawi się w obu zapytaniach, standardowe UNION zwróci go tylko raz. Działa to podobnie do zastosowania unikalności całych wierszy, a nie pojedynczej kolumny.

Poszczególne zapytania nie muszą pobierać danych z tej samej tabeli. Istotne jest to, aby ich wyniki dało się ułożyć w ten sam schemat. W praktyce często wykorzystuję tę konstrukcję do połączenia danych z tabel archiwalnych, bieżących albo pochodzących z różnych źródeł.

Podstawowa składnia

SELECT kolumna_1, kolumna_2
FROM tabela_a

UNION

SELECT kolumna_1, kolumna_2
FROM tabela_b;

Można połączyć więcej niż dwa zapytania, dokładając kolejne operatory. Każdy następny SELECT musi jednak zachować ten sam układ kolumn. Nazwy kolumn w końcowym rezultacie zwykle pochodzą z pierwszego zapytania.

UNION czy UNION ALL

Najważniejszy wybór dotyczy tego, czy duplikaty mają zostać usunięte. UNION wykonuje dodatkową operację porównywania wierszy, natomiast UNION ALL zwraca wszystkie rekordy dokładnie tak, jak pojawiły się w zapytaniach źródłowych.

Operator Duplikaty Wydajność Typowe zastosowanie
UNION Usuwa identyczne wiersze Zwykle niższa Lista unikalnych wartości z wielu źródeł
UNION ALL Zachowuje wszystkie wiersze Zwykle wyższa Raporty, agregacje i łączenie pełnych danych

Przykład z zamówieniami pokazuje różnicę najlepiej. Jeżeli ten sam produkt występuje w dwóch tabelach sprzedażowych i oba rekordy mają pozostać widoczne, użyję UNION ALL.

SELECT produkt, ilosc
FROM sprzedaz_styczen

UNION ALL

SELECT produkt, ilosc
FROM sprzedaz_luty;

Gdybym zastosował zwykły UNION, identyczne wiersze mogłyby zostać zredukowane. To nie zawsze jest korzystne. W raporcie sprzedaży dwa takie same rekordy mogą oznaczać dwie osobne transakcje, a nie błąd do usunięcia.

Moja praktyczna zasada jest prosta: zaczynam od UNION ALL, jeśli nie mam konkretnego powodu do deduplikacji. UNION wybieram świadomie, gdy usunięcie identycznych wierszy jest częścią logiki biznesowej.

Warunki poprawnego połączenia zapytań

Najczęstszy błąd polega na założeniu, że wystarczy pobrać „jakieś” kolumny z obu tabel. SQL wymaga zgodności struktury wyników. Każda część konstrukcji musi zwracać taką samą liczbę kolumn, a odpowiadające sobie pozycje powinny mieć kompatybilne typy.

Liczba i kolejność kolumn

SELECT imie, nazwisko, email
FROM klienci

UNION

SELECT nazwa, email
FROM firmy;

Ten przykład zakończy się błędem, ponieważ pierwsze zapytanie zwraca trzy kolumny, a drugie tylko dwie. Problemem może być również inna kolejność danych. SQL nie dopasowuje kolumn po nazwach, lecz po ich pozycji.

Jeżeli druga tabela przechowuje nazwę firmy i adres kontaktowy, trzeba jawnie dopasować wynik, na przykład przez dodanie wartości NULL:

SELECT imie AS nazwa, email, 'osoba' AS typ
FROM klienci

UNION ALL

SELECT nazwa, email, 'firma' AS typ
FROM kontrahenci;

Dodanie kolumny typ jest bardzo użyteczne. Dzięki niemu wiadomo, skąd pochodzi rekord, nawet gdy oba źródła zostały połączone w jeden wynik. Właśnie takie małe oznaczenie często oszczędza później sporo pracy podczas analizy danych.

Typy danych

Kolumny na tych samych pozycjach nie muszą mieć identycznego typu, ale baza musi móc je bezpiecznie połączyć. Liczba całkowita i liczba dziesiętna zwykle nie są problemem, natomiast zestawienie daty z tekstem albo liczby z niekonwertowalnym tekstem może zakończyć się błędem.

SELECT id, data_zamowienia
FROM zamowienia

UNION ALL

SELECT id, data_reklamacji
FROM reklamacje;

Jeżeli typy są niejednoznaczne, lepiej użyć jawnego CAST niż liczyć na automatyczną konwersję zależną od silnika. Takie podejście zwiększa przenośność zapytania między PostgreSQL, MySQL i SQL Server.

SELECT id, CAST(data_zdarzenia AS DATE) AS data
FROM logi_aplikacji

UNION ALL

SELECT id, CAST(data_zgloszenia AS DATE) AS data
FROM zgloszenia;

Aliasy i wartości stałe

Alias nadany kolumnie w drugim zapytaniu nie zmienia nazwy kolumny w końcowym wyniku. O tym decyduje pierwszy SELECT. Jeśli nazwa ma być czytelna, umieszczam alias właśnie tam.

SELECT nazwa AS element, 'produkt' AS zrodlo
FROM produkty

UNION ALL

SELECT nazwa, 'usluga'
FROM uslugi;

Wartości tekstowe, takie jak 'produkt' i 'usluga', pozwalają zachować informację o pochodzeniu danych. To lepsze rozwiązanie niż próba odgadywania źródła na podstawie samej wartości.

UNION a JOIN czyli dwie różne operacje

UNION i JOIN bywają mylone, bo oba służą do pracy z wieloma tabelami. Różnica jest jednak fundamentalna. Pierwszy operator dokłada wiersze pionowo, a drugi zestawia kolumny z powiązanych rekordów.

Pytanie Właściwe rozwiązanie Co powstaje
Chcę połączyć klientów z dwóch tabel UNION Więcej wierszy
Chcę dodać nazwę miasta do klienta JOIN Więcej kolumn
Chcę znaleźć wspólne rekordy INTERSECT lub JOIN Rekordy spełniające warunek dopasowania

Załóżmy, że mamy tabelę klienci oraz zamowienia. Aby pobrać klientów wraz z ich zamówieniami, użyję połączenia:

SELECT k.imie, z.numer_zamowienia
FROM klienci k
JOIN zamowienia z ON z.klient_id = k.id;

Jeśli natomiast chcę stworzyć wspólną listę osób i firm, które mają konta w systemie, lepszy będzie operator zbiorowy:

SELECT nazwa, email
FROM osoby

UNION ALL

SELECT nazwa, email
FROM firmy;

Dobra diagnoza jest prosta. Gdy potrzebuję więcej rekordów, myślę o UNION. Gdy potrzebuję informacji z tego samego rekordu rozłożonych w kilku tabelach, wybieram JOIN. Ta różnica eliminuje sporą część nieporozumień już na etapie projektowania zapytania.

Filtrowanie sortowanie i ograniczanie wyniku

Warunki WHERE zwykle umieszcza się wewnątrz poszczególnych zapytań. Dzięki temu każde źródło może mieć własne kryteria filtrowania.

SELECT imie, email
FROM klienci
WHERE aktywny = 1

UNION ALL

SELECT imie, email
FROM pracownicy
WHERE email IS NOT NULL;

Jeśli filtr ma dotyczyć całego połączonego wyniku, można opakować konstrukcję w zapytanie zewnętrzne. To czytelniejsze niż powtarzanie identycznego warunku w każdej części.

SELECT *
FROM (
    SELECT imie, email FROM klienci
    UNION ALL
    SELECT imie, email FROM pracownicy
) AS osoby
WHERE email LIKE '%@firma.pl';

Sortowanie całego rezultatu wykonuje się zazwyczaj jednym poleceniem ORDER BY na końcu:

SELECT imie, email
FROM klienci

UNION ALL

SELECT imie, email
FROM pracownicy

ORDER BY imie;

Sortowanie wewnątrz pojedynczego zapytania bez odpowiedniego opakowania często nie daje oczekiwanego efektu albo jest odrzucane przez konkretny silnik. Podobnie działa LIMIT lub TOP. Jeśli chcę pobrać pięć rekordów z każdego źródła, ograniczenie musi znaleźć się w obu zapytaniach, zwykle z użyciem nawiasów.

(SELECT imie FROM klienci ORDER BY imie LIMIT 5)
UNION ALL
(SELECT imie FROM pracownicy ORDER BY imie LIMIT 5);

Składnia szczegółowa zależy od bazy. PostgreSQL używa między innymi LIMIT, SQL Server zwykle TOP lub OFFSET ... FETCH, a MySQL również obsługuje LIMIT. Przed przeniesieniem zapytania między systemami sprawdzam właśnie te elementy.

Typowe błędy i wpływ na wydajność

Najbardziej zdradliwy błąd nie zawsze powoduje komunikat. Zapytanie może wykonać się poprawnie, ale zwrócić dane w złym układzie, jeśli kolumny zostały ustawione w niewłaściwej kolejności. Z tego powodu unikam SELECT * w konstrukcjach z UNION.

  • Użycie SELECT * może zepsuć zapytanie po dodaniu kolumny do jednej z tabel.
  • Niepotrzebny UNION usuwa duplikaty, choć raport powinien zachować wszystkie zdarzenia.
  • Brak jawnego CAST może wywołać różne wyniki w różnych silnikach baz danych.
  • ORDER BY w złym miejscu sortuje tylko fragment albo powoduje błąd składni.
  • Łączenie nieporównywalnych danych utrudnia późniejszą analizę, nawet gdy baza zaakceptuje konwersję.

Wydajność zależy przede wszystkim od ilości danych i sposobu usuwania duplikatów. UNION może wymagać sortowania albo budowy struktury pomocniczej do sprawdzenia unikalności, więc przy milionach wierszy różnica względem UNION ALL potrafi być odczuwalna.

Nie oznacza to jednak, że zawsze należy wybierać szybszy wariant. Jeżeli wynik ma przedstawiać unikalne osoby, produkty lub identyfikatory, usunięcie duplikatów jest częścią poprawności, a nie optymalizacji. Najpierw ustalam znaczenie danych, a dopiero później patrzę na plan wykonania i indeksy.

Przeczytaj również: DDL w SQL - Jak bezpiecznie zmieniać strukturę bazy danych?

Jak poprawić zapytanie

W praktyce pomaga kilka prostych nawyków. Jawnie wypisuję kolumny, filtruję dane możliwie wcześnie i stosuję UNION ALL, gdy rekordy z różnych źródeł mają zachować swoją pełną liczność.

  1. Sprawdź liczbę i kolejność kolumn w każdym SELECT.
  2. Porównaj typy danych i dodaj CAST, jeśli konwersja nie jest oczywista.
  3. Zdecyduj, czy duplikat oznacza błąd, czy osobne zdarzenie.
  4. Przenieś wspólne filtrowanie do zapytania zewnętrznego, jeśli poprawia czytelność.
  5. Przy dużych tabelach sprawdź plan wykonania i rzeczywisty czas działania.

Jak wykorzystać UNION w codziennej pracy

Najbardziej praktyczne zastosowanie to łączenie tabel o podobnej strukturze, na przykład danych bieżących i archiwalnych. Takie rozwiązanie bywa przydatne w raportach, migracjach, konsolidacji danych oraz podczas budowania warstwy analitycznej.

SELECT id, kwota, data_platnosci, 'bieżące' AS zrodlo
FROM platnosci

UNION ALL

SELECT id, kwota, data_platnosci, 'archiwalne' AS zrodlo
FROM platnosci_archiwum;

Kolumna zrodlo jest tutaj ważniejsza, niż może się wydawać. Pozwala szybko wykryć, z której tabeli pochodzi rekord, a później porównać liczbę płatności lub sumy między źródłami.

Można też połączyć wyniki o różnym pochodzeniu, o ile przygotuje się wspólny format:

SELECT nazwa, cena, 'produkt' AS kategoria
FROM produkty

UNION ALL

SELECT nazwa, stawka AS cena, 'usługa' AS kategoria
FROM uslugi;

Nie próbowałbym jednak używać tego operatora jako sposobu na ukrywanie złego modelu danych. Jeżeli regularnie łączysz kilkanaście tabel o podobnej strukturze, być może lepszym rozwiązaniem będzie wspólna tabela, widok albo partycjonowanie. UNION jest świetnym narzędziem integracyjnym, ale nie zastąpi przemyślanego schematu bazy.

Świadomy wybór operatora zaczyna się od znaczenia wiersza

Najkrócej mówiąc, UNION buduje wspólny wynik z kilku zapytań, a UNION ALL robi to bez usuwania duplikatów. Właściwy wybór zależy od tego, czy dwa identyczne wiersze opisują ten sam fakt, czy dwa niezależne zdarzenia.

Przed uruchomieniem zapytania sprawdzam trzy rzeczy: układ kolumn, sens duplikatów i oczekiwaną kolejność danych. Ten krótki test zwykle daje więcej niż późniejsze poprawianie raportu, który wygląda poprawnie, ale zgubił część rekordów.

Jeżeli dane pochodzą z różnych źródeł, dodaję kolumnę opisującą ich pochodzenie i jawnie określam typy. Dzięki temu operator pozostaje prosty, wynik jest łatwiejszy do kontroli, a zapytanie można bezpieczniej wykorzystać także z poziomu aplikacji napisanej w Pythonie.

FAQ - Najczęstsze pytania

UNION usuwa identyczne wiersze, dlatego sprawdza się przy tworzeniu list unikalnych wartości. UNION ALL zachowuje wszystkie rekordy i zwykle działa szybciej, więc lepiej pasuje do raportów, agregacji oraz danych, w których powtórzenia oznaczają osobne zdarzenia.

Każdy SELECT musi zwracać taką samą liczbę kolumn w tej samej kolejności. Odpowiadające sobie kolumny powinny mieć zgodne lub konwertowalne typy danych. Gdy konwersja jest niejednoznaczna, warto użyć jawnego CAST.

UNION dokłada wyniki zapytań pionowo, tworząc więcej wierszy. JOIN łączy powiązane rekordy poziomo, dodając kolumny z kilku tabel. Do wspólnej listy osób i firm użyjesz UNION, a do pobrania klientów wraz z ich zamówieniami - JOIN.

Jeśli sortowanie ma objąć cały połączony wynik, ORDER BY umieszcza się zazwyczaj na końcu konstrukcji. Warunki WHERE można stosować osobno w każdym SELECT. Wspólny filtr dla całego rezultatu wymaga opakowania UNION w zapytanie zewnętrzne.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

union
union all
join
cast
deduplikacja
Autor Konstanty Jankowski
Konstanty Jankowski
Nazywam się Konstanty Jankowski i od sześciu lat zajmuję się programowaniem, szczególnie w języku Python oraz nowoczesnymi technologiami. Moje zainteresowanie tymi tematami zrodziło się podczas studiów, kiedy odkryłem, jak wiele możliwości stwarza programowanie w codziennym życiu. Lubię dzielić się swoją wiedzą i pomagać innym zrozumieć złożoność zagadnień związanych z technologią. W moich tekstach skupiam się na praktycznych aspektach programowania, analizując aktualne trendy oraz uproszczając trudne koncepcje, aby były dostępne dla każdego. Dokładam wszelkich starań, aby dostarczać rzetelne, zrozumiałe i aktualne informacje. Staram się porównywać różne źródła i organizować wiedzę w sposób jasny, co pozwala mi na skuteczne przekazywanie informacji. Wierzę, że dobra edukacja w obszarze programowania i technologii może otworzyć drzwi do wielu fascynujących możliwości.

Udostępnij artykuł

Napisz komentarz