CodeGym /Kursy /SQL SELF /Funkcje GREATEST() i LEAST() oraz NULL

Funkcje GREATEST() i LEAST() oraz NULL

SQL SELF
Poziom 10 , Lekcja 2
Dostępny

Dziś zanurzymy się w jeszcze bardziej specyficzny, ale ważny temat: funkcje GREATEST() i LEAST(). Dowiesz się, jak znaleźć największe i najmniejsze wartości z kilku kolumn i – co najważniejsze – jak NULL wpływa na ich działanie.

Jeśli kiedyś szukałeś najważniejszej rzeczy w swoim życiu (miłości, wymarzonej pracy albo najlepszego przepisu na pizzę), to od razu załapiesz, po co są funkcje GREATEST() i LEAST(). Te funkcje pomagają znaleźć największą lub najmniejszą wartość na liście rzeczy. Tylko zamiast pizzy pracujesz z liczbami, datami, stringami i innymi danymi w PostgreSQL.

GREATEST()

GREATEST() zwraca największą wartość z przekazanego zestawu.

Składnia:

GREATEST(value1, value2, ..., valueN)

LEAST()

LEAST() robi odwrotnie: szuka najmniejszej wartości.

Składnia:

LEAST(value1, value2, ..., valueN)

Przykład:

Załóżmy, że mamy tabelę students_scores, gdzie trzymamy oceny studentów z trzech egzaminów:

student_id exam_1 exam_2 exam_3
1 85 90 82
2 NULL 76 89
3 94 NULL 88

Użycie GREATEST() i LEAST():

SELECT
    student_id,
    GREATEST(exam_1, exam_2, exam_3) AS highest_score,
    LEAST(exam_1, exam_2, exam_3) AS lowest_score
FROM students_scores;

Wynik:

student_id highest_score lowest_score
1 90 82
2 89 NULL
3 94 NULL

Jak NULL wpływa na GREATEST() i LEAST()

No i teraz robi się najciekawiej. W tabeli razem z wartościami mogą pojawić się też NULL. A jak już wiemy, NULL to taka tajemnicza istota, która oznacza brak danych albo nieznaną wartość. Sprawdźmy, co się dzieje, jeśli NULL trafi do funkcji GREATEST() i LEAST() w PostgreSQL.

Zachowanie NULL:

W PostgreSQL funkcje GREATEST() i LEAST() mają specjalne zachowanie: ignorują wartości NULL przy szukaniu największej lub najmniejszej wartości wśród swoich argumentów. Ważne: Jedyny przypadek, kiedy te funkcje zwrócą NULL, to jeśli wszystkie ich argumenty są NULL.

Przykład:

SELECT
    GREATEST(10, 20, NULL, 5) AS greatest_value,
    LEAST(10, 20, NULL, 5) AS least_value;

Wynik:

greatest_value least_value
20 5

Jak widzisz, NULL został zignorowany i funkcje zwróciły największą i najmniejszą wartość z obecnych (10, 20, 5).

A tu przykład, gdy wszystkie argumenty to NULL:

Przykład:

SELECT
    GREATEST(NULL, NULL) AS greatest_nulls,
    LEAST(NULL, NULL) AS least_nulls;

Wynik:

greatest_nulls least_nulls
NULL NULL

Jak uniknąć problemów z NULL?

Chociaż PostgreSQL domyślnie ignoruje NULL, czasem możesz chcieć inne zachowanie. Na przykład, jeśli chcesz, żeby NULL był traktowany jako konkretna wartość (np. 0 albo coś innego domyślnego) przy określaniu największej/najmniejszej. W takich sytuacjach możesz użyć funkcji COALESCE().

Funkcja COALESCE(arg1, arg2, ...) zwraca pierwszy nie-NULL argument ze swojej listy. Dzięki temu możesz wcześniej podmienić NULL na sensowną wartość przed przekazaniem do GREATEST() albo LEAST().

Przykład 1: Zamiana NULL na 0

Załóżmy, że chcemy uznać brak oceny NULL za 0. Możemy użyć COALESCE(), żeby podstawić wartość domyślną.

Oto nasza wyjściowa tabela:

student_id exam_1 exam_2 exam_3
1 90 85 82
2 NULL 89 NULL
3 NULL NULL 94

Zapytanie:

SELECT
    student_id,
    GREATEST(
        COALESCE(exam_1, 0), 
        COALESCE(exam_2, 0), 
        COALESCE(exam_3, 0)
    ) AS highest_score,
    LEAST(
        COALESCE(exam_1, 0), 
        COALESCE(exam_2, 0), 
        COALESCE(exam_3, 0)
    ) AS lowest_score
FROM students_scores;

Wynik:

student_id highest_score lowest_score
1 90 82
2 89 0
3 94 0

Przykład 2: Zamiana NULL na wartość z innej kolumny

Czasem zamiast stałej wartości (np. 0) trzeba podstawić wartość z innej kolumny. Na przykład, jeśli exam_3 nie ma, chcemy użyć wartości z exam_1.

SELECT
    student_id,
    GREATEST(
        exam_1, 
        exam_2, 
        COALESCE(exam_3, exam_1)
    ) AS highest_score
FROM students_scores;

Załóżmy, że mamy taką tabelę:

student_id exam_1 exam_2 exam_3
1 90 85 82
2 NULL 89 NULL
3 70 NULL NULL

Wynik działania zapytania:

student_id highest_score
1 90
2 89
3 70

Praktyczne case'y

Case 1: Szukanie maksymalnej zniżki

order_id discount_1 discount_2 discount_3
101 5 10 7
102 NULL 3 8
103 15 NULL NULL
104 NULL NULL NULL

Pracujesz z tabelą orders, gdzie każde zamówienie może mieć trzy różne typy zniżek. Musisz znaleźć największą ze wszystkich zniżek dla każdego zamówienia.

SELECT
    order_id,
    GREATEST(discount_1, discount_2, discount_3) AS max_discount
FROM orders;

Wynik:

order_id max_discount
101 10
102 8
103 15
104 NULL

Case 2: Szukanie minimalnej ceny produktu

W tabeli products trzymane są ceny produktów w trzech walutach (USD, EUR, GBP). Twoje zadanie – znaleźć minimalną cenę dla każdego produktu.

product_id price_usd price_eur price_gbp
1 100 95 80
2 NULL 150 140
3 200 NULL NULL
4 NULL NULL NULL
SELECT
    product_id,
    LEAST(price_usd, price_eur, price_gbp) AS lowest_price
FROM products;
product_id lowest_price
1 80
2 140
3 200
4 NULL

Jeśli wszystkie ceny to NULL, wynik też będzie NULL

Typowe błędy przy użyciu GREATEST() i LEAST()

Błąd 1: Nieoczekiwany wynik przez NULL.

Wcześniej w wykładzie dokładnie omówiliśmy, jak NULL wpływa na GREATEST() i LEAST() w PostgreSQL. Główny błąd polega na tym, że użytkownicy przyzwyczajeni do zachowania NULL w innych bazach (gdzie jeden NULL "zatruwa" cały wynik), spodziewają się tego samego po PostgreSQL.

Jak się objawia błąd: Możesz błędnie założyć, że jeśli wśród argumentów jest NULL, funkcja zawsze zwróci NULL. W efekcie możesz niepotrzebnie używać COALESCE() do wszystkich argumentów, co może skomplikować zapytanie i spowolnić jego wykonanie, jeśli w twoim przypadku NULL powinien być po prostu zignorowany.

Błąd 2: Użycie GREATEST() i LEAST() z niekompatybilnymi typami.

Funkcje GREATEST() i LEAST() są przeznaczone do porównywania wartości tego samego typu danych albo typów, które mogą być niejawnie przekonwertowane do siebie. Próba porównania zupełnie różnych, niekompatybilnych typów skończy się błędem.

Jak się objawia błąd: Dostaniesz komunikat o błędzie, wskazujący na niezgodność typów danych.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION