221 votes

Obtenir le minimum de deux valeurs en SQL

J'ai deux variables, l'une s'appelle PaidThisMonth, et l'autre s'appelle OwedPast. Ce sont tous deux des résultats de certaines sous-requêtes en SQL. Comment puis-je sélectionner le plus petit des deux et le retourner comme une valeur intitulée PaidForPast?

La fonction MIN fonctionne sur les colonnes, pas sur les variables.

5 votes

Si vous êtes sur Postgres ou MySQL, passez à la réponse de @Gil_Margolin.

190voto

Crimson Points 31

SQL Server 2012 et 2014 prend en charge la fonction IIF(cont,vrai,faux). Ainsi, pour une sélection minimale, vous pouvez l'utiliser comme suit

SELECT IIF(premier>deuxième, deuxième, premier) le_minimal FROM table

Alors que IIF est simplement un raccourci pour écrire CASE...WHEN...ELSE, c'est plus facile à écrire.

9 votes

IIF est juste un sucre syntaxique pour CASE...WHEN...ELSE.

66 votes

Peut-être oui. Mais plus facile à écrire.

8 votes

@MertGülsoy Et plus facile à lire, ce qui devrait être en tête de la liste des priorités de chacun, juste après la correction.

144voto

Charles Bretana Points 59899

Scénario d'utilisation :

   Select Case When @PaidThisMonth < @OwedPast 
               Then @PaidThisMonth Else @OwedPast End PaidForPast

Comme une fonction UDF à table à valeurs Inline

CREATE FUNCTION Minimum
(@Param1 Integer, @Param2 Integer)
Returns Table As
Return(Select Case When @Param1 < @Param2 
                   Then @Param1 Else @Param2 End MinValue)

Utilisation :

Select MinValue as PaidforPast 
From dbo.Minimum(@PaidThisMonth, @OwedPast)

ADDENDUM: C'est probablement mieux lorsque l'on traite uniquement deux valeurs possibles, s'il y en a plus de deux, envisagez la réponse de Craig en utilisant la clause Values.

0 votes

Syntaxe plus compréhensible : retourner (sélectionnez minValue = cas quand @@param1 < @@param2 alors @@param1 sinon @@param2 fin). Ok cela peut ne pas être normalisé, je ne sais pas. Mais c'est beaucoup plus compréhensible et devrait être normalisé.

1 votes

Une autre raison de préférer la réponse de @Craig ci-dessous est liée à la gestion de la valeur nulle. Si les valeurs comparées sont nulles, et l'une des valeurs comparées est nulle, le cas du switch-case montré pourrait renvoyer null ou la valeur, selon l'ordre du test WHEN (sauf si vous ajoutez l'utilisation de ISNULL). L'approche de Craig préférera toujours la sélection de la valeur non nulle, ce qui me semble plus correct, du moins dans mon cas d'utilisation actuel dans la comparaison de dates nullables.

36voto

MartinC Points 151

J'ai eu une situation où j'ai dû trouver le maximum de 4 sélections complexes dans une mise à jour. Avec cette approche, vous pouvez en avoir autant que vous le souhaitez!

Vous pouvez également remplacer les numéros par des sélections supplémentaires

select max(x)
 from (
 select 1 as 'x' union
 select 4 as 'x' union
 select 3 as 'x' union
 select 2 as 'x' 
 ) a

Utilisation plus complexe

 @answer = select Max(x)
           from (
                select @NumberA as 'x' union
                select @NumberB as 'x' union
                select @NumberC as 'x' union
                select (
                       Select Max(score) from TopScores
                       ) as 'x' 
     ) a

Je suis sûr qu'une UDF a de meilleures performances.

0 votes

J'aime ceci le plus car c'est du SQL de base. De plus, les UDF ne sont pas nécessairement plus rapides. Pour la plupart des magasins de colonnes, chaque attribut (je suppose que vous allez également filtrer sur les attributs) peut être calculé en parallèle et seul l'ensemble qualifiant est uni. Donc, les unions ne sont pas inherently slow.

6voto

Mike Cole Points 4063

Utilisez une déclaration CASE.

L'exemple B de cette page devrait être proche de ce que vous essayez de faire :
http://msdn.microsoft.com/en-us/library/ms181765.aspx

Voici le code de la page :

USE AdventureWorks;
GO
SELECT   ProductNumber, Name, 'Plage de prix' = 
      CASE 
         WHEN ListPrice =  0 THEN 'Article de fabrication - non destiné à la revente'
         WHEN ListPrice < 50 THEN 'Moins de 50 $'
         WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Moins de 250 $'
         WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Moins de 1000 $'
         ELSE 'Plus de 1000 $'
      END
FROM Production.Product
ORDER BY ProductNumber ;
GO

3voto

Lawrence Points 11

Cela fonctionne pour jusqu'à 5 dates et gère les valeurs nulles. Je n'ai juste pas réussi à le faire fonctionner en tant que fonction Inline.

CREATE FUNCTION dbo.MinDate(@Date1 datetime = Null,
                            @Date2 datetime = Null,
                            @Date3 datetime = Null,
                            @Date4 datetime = Null,
                            @Date5 datetime = Null)
RETURNS Datetime AS
BEGIN
--UTILISATION select dbo.MinDate('20120405',null,null,'20110305',null)
DECLARE @Output datetime;

WITH Datelist_CTE(DT)
AS (
        SELECT @Date1 AS DT WHERE @Date1 is not NULL UNION
        SELECT @Date2 AS DT WHERE @Date2 is not NULL UNION
        SELECT @Date3 AS DT WHERE @Date3 is not NULL UNION
        SELECT @Date4 AS DT WHERE @Date4 is not NULL UNION
        SELECT @Date5 AS DT WHERE @Date5 is not NULL
   )
Select @Output=Min(DT) FROM Datelist_CTE;

RETURN @Output;
END;

0 votes

Je viens de réaliser que vous n'avez pas besoin des clauses WHERE car MIN supprimera de toute façon les valeurs nulles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X