web-dev-qa-db-fra.com

MySQL: obtient le MAX ou le PLUS GRAND de plusieurs colonnes, mais avec des champs NULL

J'essaie de sélectionner la date maximum dans trois champs différents dans chaque enregistrement (MySQL) Ainsi, dans chaque ligne, j'ai date1, date2 et date3: date1 est toujours rempli, date2 et date3 peuvent être vides ou nuls L’instruction GREATEST est simple et concise mais n’a aucun effet sur les champs NULL. Elle ne fonctionne donc pas bien:

SELECT id, GREATEST(date1, date2, date3) as datemax FROM mytable

J'ai aussi essayé des solutions plus complexes comme celle-ci:

SELECT
    CASE
        WHEN date1 >= date2 AND date1 >= date3 THEN date1
        WHEN date2 >= date1 AND date2 >= date3 THEN date2
        WHEN date3 >= date1 AND date3 >= date2 THEN date3
        ELSE                                        date1
    END AS MostRecentDate

Même problème ici: les valeurs NULL sont un très bon problème pour retourner les bons enregistrements

S'il vous plaît, avez-vous une solution? Merci d'avance ....

46
Ivan

Utilisez COALESCE

SELECT id, 
   GREATEST(date1, 
     COALESCE(date2, 0),
     COALESCE(date3, 0)) as datemax 
FROM mytable

Mise à jour: Cette réponse utilisait précédemment IFNULL qui fonctionne, mais comme Mike Chamberlain l'a souligné dans les commentaires, COALESCE est en fait la méthode préférée.

85
Matt Dodge

Si date1 ne peut jamais être NULL, le résultat ne devrait jamais être NULL, n'est-ce pas? Vous pouvez ensuite utiliser ceci si vous souhaitez que les dates NULL ne soient pas comptées dans les calculs (ou remplacez le 1000-01-01 par 9999-12-31 si vous souhaitez que Nulls compte comme "fin du temps"):

GREATEST( date1
        , COALESCE(date2, '1000-01-01')
        , COALESCE(date3, '1000-01-01')
        ) AS datemax
30
ypercubeᵀᴹ

COALESCE vos colonnes de date avant de les utiliser dans GREATEST.

La façon dont vous les manipulerez dépendra de la manière dont vous souhaitez gérer NULL .. haut ou bas?

5
hkf

buuut, si toutes les dates sont nulles? vous voulez toujours avoir null comme sortie, non? alors vous avez besoin de ça

select nullif(greatest(coalesce(<DATEA>, from_unixtime(0)), coalesce(<DATEB>, from_unixtime(0))), from_unixtime(0));

Maintenant, si les deux sont nuls, vous obtenez null, si l'un d'eux n'est pas nul, les deux ne sont pas nuls, vous obtenez le meilleur.

C'est fou, surtout si vous allez l'utiliser plusieurs fois, alors vous voudrez peut-être le créer comme une fonction, comme ceci:

delimiter //
drop function if exists cp_greatest_date//
create function cp_greatest_date ( dateA timestamp, dateB timestamp ) returns timestamp
  deterministic reads sql data
  begin

    # if both are null you get null, if one of them is not null of both of them are not null, you get the greatest
    set @output = nullif(greatest(coalesce(dateA, from_unixtime(0)), coalesce(dateB, from_unixtime(0))), from_unixtime(0));
    # santiago arizti

    return @output;
  end //
delimiter ;

Ensuite, vous pouvez l'utiliser comme ça

select cp_greatest_date(current_timestamp, null);
-- output is 2017-05-05 20:22:45
0
santiago arizti