COALESCE w SQL - jak działa NULL, pusty tekst i typ wyniku

Przemysław Kwiatkowski • 3 listopada 2026
Szkolenie z języka SQL z AI, gdzie AI analizuje plany wykonania z SSMS, pomagając optymalizować zapytania, np. poprzez sugerowanie brakujących indeksów, jak w przypadku CustomerID.

Spis treści

Raport klienta ma pokazać numer telefonu, ale część rekordów zawiera `NULL` w kolumnie z numerem firmowym. W takim przypadku `COALESCE` zwróci pierwszą wartość, która nie jest `NULL`, choć przy wyrażeniach zależnych od danych wynik może zaskoczyć.

COALESCE wybiera wartość według kolejności argumentów

  • Zwraca pierwszy argument różny od `NULL`, a gdy wszystkie są `NULL`, wynikiem też jest `NULL`.
  • Kolejność ma znaczenie: `COALESCE(telefon_firmowy, telefon_prywatny, 'brak')` daje pierwszeństwo numerowi firmowemu.
  • Pusty tekst i zero nie są `NULL`, więc funkcja ich nie zastąpi.
  • W SQL Server typ wyniku zależy od hierarchii typów, a podzapytanie w argumentach może zostać wykonane więcej niż raz.

COALESCE wybiera pierwszą nie-NULL-ową wartość z listy

Gdy kilka kolumn może zawierać tę samą informację, ale tylko jedna jest wypełniona, funkcja pozwala określić kolejność źródeł zastępczych. Przykładowo w tabeli klientów numer służbowy może mieć pierwszeństwo przed prywatnym.

SELECT
    COALESCE(telefon_firmowy, telefon_prywatny, 'brak telefonu') AS telefon
FROM Klienci;

Jeśli `telefon_firmowy` ma wartość, zostanie zwrócona właśnie ona. Gdy jest `NULL`, SQL sprawdzi następną kolumnę, a tekst `brak telefonu` trafi do wyniku dopiero wtedy, gdy oba numery będą `NULL`.

Podobnie można ustawić wartość domyślną dla danych prezentowanych w raporcie: `COALESCE(opis, opis_skrocony, 'Brak opisu')`. Prawdę mówiąc, sama zwięzłość nie powinna przesłonić pytania, czy pusta wartość faktycznie oznacza brak danych.

Reguła zastępowania zależy od tego, co naprawdę oznacza NULL

Najłatwiej wpaść w pułapkę, gdy `NULL` potraktuje się jak uniwersalne „brak”. Pusty tekst może oznaczać wprowadzoną, lecz pustą wartość, a zero może być prawidłowym wynikiem, na przykład saldem po rozliczeniu.

`COALESCE('', 'domyślny tekst')` zwróci pusty tekst, a `COALESCE(0, 100)` zwróci zero. Jeśli pusty ciąg również ma uruchamiać wartość domyślną, trzeba najpierw zamienić go na `NULL`, na przykład za pomocą `NULLIF`:

SELECT COALESCE(NULLIF(nazwa, ''), 'Brak nazwy') AS nazwa
FROM Produkty;

Przed dodaniem funkcji ustal więc regułę biznesową: czy zastępujesz wyłącznie brak wartości w bazie, czy również puste dane i określone wartości liczbowe. Te przypadki wymagają innych warunków, nawet jeśli w raporcie mają wyglądać podobnie.

W SQL Server COALESCE i ISNULL mogą dać inny typ wyniku

Dwa zapytania mogą wyświetlić podobny tekst, a mimo to zwrócić wynik o innym typie. W SQL Server `COALESCE` wybiera typ o najwyższym priorytecie spośród argumentów, natomiast `ISNULL` przyjmuje typ pierwszego argumentu; opisuje to dokumentacja Microsoft Learn.

DECLARE @kod varchar(10) = NULL;

SELECT COALESCE(@kod, N'brak') AS wynik_coalesce,
       ISNULL(@kod, N'brak') AS wynik_isnull;

W tym przykładzie `COALESCE` może zwrócić typ `nvarchar`, bo tekst Unicode ma wyższy priorytet niż `varchar`. `ISNULL` opiera typ wyniku na pierwszym argumencie, więc warto sprawdzić, czy tekst zastępczy nie zostanie obcięty podczas konwersji.

Gdy typ ma być jednoznaczny, jawnie rzutuj argumenty do docelowego formatu, np. `COALESCE(CAST(@kod AS nvarchar(30)), N'brak')`. A jeśli przenosisz zapytanie między silnikami, nie zakładaj, że `ISNULL` znaczy to samo wszędzie: w MySQL nazwa ta służy do sprawdzania, czy argument jest `NULL`, a do podmiany wartości używa się `IFNULL` albo przenośnego `COALESCE`.

Podzapytanie w COALESCE może zostać wykonane więcej niż raz

Prosty przykład z kolumnami nie zdradza istotnego wyjątku. W SQL Server `COALESCE` jest przekształcane do konstrukcji podobnej do `CASE`, dlatego wyrażenie zawierające podzapytanie może zostać ocenione ponownie; Microsoft Learn zwraca uwagę, że przy `READ COMMITTED` odczyty w środowisku wieloużytkownikowym mogą wtedy dać różne wyniki.

SELECT COALESCE(
    (SELECT Status
     FROM Zamowienia
     WHERE Id = @id),
    'nieznany'
);

Gdy podzapytanie zależy od danych, które równolegle mogą się zmienić, nie traktuj go jak jednorazowego odczytu. Możesz wyciągnąć je do podzapytania w `FROM`, użyć odpowiedniego poziomu izolacji albo rozważyć `ISNULL`, jeśli zapytanie jest przeznaczone wyłącznie dla SQL Server i jego różnice w typowaniu oraz obsłudze `NULL` pasują do przypadku.

Dokumentacja PostgreSQL opisuje pomijanie argumentów po znalezieniu pierwszej nie-`NULL`-owej wartości. Ta intuicja dobrze opisuje typowe użycie, ale nie powinna zastępować sprawdzenia zachowania konkretnego silnika, zwłaszcza gdy argumentem jest kosztowne lub zmienne podzapytanie.

COALESCE w WHERE może zmienić sens filtra

Umieszczenie `COALESCE` w warunku bywa krótsze, ale warto sprawdzić, czy podstawiona wartość nie zmieni zestawu wyników ani sposobu użycia indeksu. Gdy szukasz rekordu o konkretnym statusie albo porównujesz kolumnę z wartością domyślną, funkcja może zlać dwa różne przypadki w jeden.

SytuacjaMożliwy skutekCo zrobić
Filtr `WHERE COALESCE(status, 'nowy') = 'nowy'`Pasują zarówno rekordy z `status = 'nowy'`, jak i te z `status IS NULL`.Jeśli brak statusu ma być osobnym przypadkiem, użyj jawnego warunku `status = 'nowy' OR status IS NULL` albo rozdziel logikę.
W argumencie jest podzapytanie zależne od zmiennych danychW SQL Server ponowna ewaluacja może odczytać inny stan danych.Przenieś podzapytanie do osobnego poziomu zapytania lub dobierz izolację odpowiednią do wymaganego odczytu.
Argumenty mają różne typy tekstowe lub liczboweSilnik może skonwertować wynik do typu o wyższym priorytecie, a w innych układach konwersja może zakończyć się błędem.Jawnie rzutuj wartości do oczekiwanego typu przed wywołaniem funkcji.
Brak danych ma być odróżniony od pustego tekstu lub zera`COALESCE` zachowa pusty tekst i zero jako prawidłowe wartości.Dodaj warunek, np. `NULLIF(kolumna, '')`, jeśli pusty tekst ma być traktowany jak brak.

Przy filtrach wybór jest prosty: jeśli brak wartości powinien zachowywać się identycznie jak domyślny status, `COALESCE` może oddać tę regułę zwięźle. Jeśli oba stany mają prowadzić do różnych decyzji, zapisz je osobno, bo skrót ukryje różnicę.

Zostaw COALESCE tam, gdzie kolejność ma sens

Najczytelniejsze zastosowanie tej funkcji to uporządkowana lista równorzędnych źródeł, na przykład kilka numerów kontaktowych z jasno ustalonym priorytetem. Wtedy intencja jest widoczna od razu, a wartość końcowa nie zależy od przypadkowego sortowania rekordów.

Uważam, że przed użyciem `COALESCE` w filtrze lub przy podzapytaniu lepiej rozpisać sobie znaczenie każdego argumentu: co ma pierwszeństwo, co oznacza `NULL` i jaki typ ma wyjść. Jeśli odpowiedź na te trzy pytania jest jasna, funkcja zwykle pozostaje prostym narzędziem zamiast maskować niejednoznaczność danych.

FAQ - Najczęstsze pytania

Zwraca pierwszy argument różny od NULL, zgodnie z kolejnością podaną w funkcji. W przykładzie COALESCE(telefon_firmowy, telefon_prywatny, 'brak telefonu') najpierw sprawdza numer firmowy, potem prywatny, a tekst zastępczy zwraca, gdy oba numery są NULL.

Nie. Pusty tekst i zero nie są NULL, więc COALESCE('', 'domyślny tekst') zwróci pusty tekst, a COALESCE(0, 100) zwróci zero. Jeśli pusty ciąg ma oznaczać brak danych, można najpierw zamienić go na NULL przez NULLIF(nazwa, '').

COALESCE wybiera typ o najwyższym priorytecie spośród argumentów, a ISNULL przyjmuje typ pierwszego argumentu. Dlatego przy varchar i tekście Unicode COALESCE może zwrócić nvarchar, podczas gdy tekst zastępczy w ISNULL może zostać skonwertowany do typu pierwszego argumentu. Aby ustalić format wyniku, jawnie rzutuj argumenty.

SQL Server przekształca COALESCE do konstrukcji podobnej do CASE, więc wyrażenie zawierające podzapytanie może zostać ocenione więcej niż raz. Przy READ COMMITTED kolejne odczyty mogą zobaczyć różne stany danych, jeśli zmieniają się równolegle. Można przenieść podzapytanie do osobnego poziomu zapytania albo dobrać poziom izolacji do wymagań odczytu.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

null
typy danych
podzapytania
filtrowanie
Autor Przemysław Kwiatkowski
Przemysław Kwiatkowski
Jestem Przemysław i od 15 lat zajmuję się programowaniem .NET, chmurą Azure oraz sztuczną inteligencją. Moja przygoda z tymi technologiami zaczęła się od fascynacji możliwościami, jakie dają, a z czasem przerodziła się w pasję do tworzenia rozwiązań, które realnie wpływają na pracę i życie ludzi. Na kursdotnet.pl staram się dzielić się swoją wiedzą w sposób przystępny, tłumacząc złożone zagadnienia i pomagając zrozumieć, jak te dynamicznie rozwijające się obszary IT mogą być wykorzystane w praktyce. Dokładam wszelkich starań, aby prezentowane przeze mnie materiały były rzetelne, aktualne i oparte na sprawdzonych źródłach, a także aby uporządkować wiedzę w sposób ułatwiający jej przyswojenie.

Udostępnij artykuł

Napisz komentarz