CodeGym /Cursos /SQL SELF /Funções GREATEST() e LEAST() e NULL

Funções GREATEST() e LEAST() e NULL

SQL SELF
Nível 10 , Lição 2
Disponível

Hoje a gente vai mergulhar num assunto mais específico, mas super importante: as funções GREATEST() e LEAST(). Você vai aprender como achar os maiores e menores valores entre várias colunas e, o mais importante, como o NULL afeta o resultado delas.

Se você já procurou o mais importante na sua vida (amor, o emprego dos sonhos ou a melhor receita de pizza), vai sacar rapidinho pra que servem as funções GREATEST() e LEAST(). Essas funções ajudam a encontrar o maior ou menor valor numa lista de coisas. Só que, em vez de pizza, você vai trabalhar com números, datas, strings e outros dados no PostgreSQL.

GREATEST()

GREATEST() retorna o maior valor do conjunto que você passar.

Sintaxe:

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

LEAST()

LEAST() faz o contrário: ela procura o menor valor.

Sintaxe:

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

Exemplo:

Imagina que a gente tem uma tabela students_scores, onde ficam as notas dos alunos em três provas:

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

Usando GREATEST() e 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;

Resultado:

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

Como o NULL afeta o GREATEST() e LEAST()

Agora vem a parte mais interessante. Junto com os valores na tabela, pode aparecer NULL. E como a gente já sabe, NULL é aquele bicho estranho que significa dado ausente ou valor desconhecido. Bora ver o que rola se NULL cair dentro das funções GREATEST() e LEAST() no PostgreSQL.

Comportamento do NULL:

No PostgreSQL, as funções GREATEST() e LEAST() têm um comportamento especial: elas ignoram os valores NULL quando estão procurando o maior ou menor valor entre os argumentos. Importante: O único caso em que essas funções vão retornar NULL é se todos os argumentos forem NULL.

Exemplo:

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

Resultado:

greatest_value least_value
20 5

Como você vê, o NULL foi ignorado e as funções devolveram o maior e o menor valor dos que estavam lá (10, 20, 5).

Agora um exemplo onde todos os argumentos são NULL:

Exemplo:

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

Resultado:

greatest_nulls least_nulls
NULL NULL

Como evitar problemas com NULL?

Mesmo que o PostgreSQL ignore o NULL por padrão, às vezes você pode querer um comportamento diferente. Por exemplo, se você quiser que o NULL seja tratado como um valor específico (tipo 0 ou outro valor padrão) na hora de achar o maior/menor. Nesses casos, dá pra usar a função COALESCE().

A função COALESCE(arg1, arg2, ...) retorna o primeiro argumento que não for NULL da lista. Isso permite trocar o NULL por um valor que faça sentido antes de passar pra GREATEST() ou LEAST().

Exemplo 1: Trocando NULL por 0

Vamos supor que a gente quer considerar que a ausência de nota (NULL) é igual a 0. Dá pra usar COALESCE() pra colocar o valor padrão.

Aqui está nossa tabela original:

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

Query:

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;

Resultado:

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

Exemplo 2: Trocando NULL pelo valor de outra coluna

Às vezes, em vez de um valor fixo (tipo 0), você quer colocar o valor de outra coluna. Por exemplo, se exam_3 estiver faltando, a gente usa o valor de exam_1.

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

Imagina que a tabela é assim:

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

Resultado da query:

student_id highest_score
1 90
2 89
3 70

Casos práticos

Caso 1: Procurando o maior desconto

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

Você está trabalhando com a tabela orders, onde cada pedido pode ter três tipos diferentes de desconto. Você precisa achar o maior desconto de cada pedido.

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

Resultado:

order_id max_discount
101 10
102 8
103 15
104 NULL

Caso 2: Procurando o menor preço do produto

Na tabela products ficam os preços dos produtos em três moedas (USD, EUR, GBP). Sua missão é achar o menor preço de cada produto.

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

Se todos os preços forem NULL, o resultado também é NULL

Erros comuns usando GREATEST() e LEAST()

Erro 1: Resultado inesperado por causa do NULL.

Lá no começo da aula a gente já explicou como o NULL afeta o GREATEST() e o LEAST() no PostgreSQL. O erro mais comum é que quem está acostumado com o comportamento do NULL em outros bancos (onde um NULL "contamina" o resultado todo) espera que o PostgreSQL faça igual.

Como esse erro aparece: Você pode achar que se tiver NULL na lista de argumentos, a função sempre vai devolver NULL. Daí, você pode acabar usando COALESCE() em tudo sem precisar, o que deixa a query mais complicada e pode até deixar ela mais lenta, se no seu caso o NULL deveria só ser ignorado.

Erro 2: Usar GREATEST() e LEAST() com tipos incompatíveis.

As funções GREATEST() e LEAST() servem pra comparar valores do mesmo tipo de dado ou tipos que podem ser convertidos automaticamente entre si. Se você tentar comparar valores de tipos totalmente diferentes, vai dar erro.

Como esse erro aparece: Você vai receber uma mensagem de erro dizendo que os tipos de dados são incompatíveis.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION