web-dev-qa-db-fra.com

Obtenir le minimum de deux valeurs en SQL

J'ai deux variables, l'une s'appelle PaidThisMonth, et l'autre s'appelle OwedPast. Ils sont tous deux le résultat de certaines sous-requêtes SQL. Comment puis-je sélectionner le plus petit des deux et le renvoyer sous la forme d'une valeur intitulée PaidForPast?

La fonction MIN fonctionne sur des colonnes et non sur des variables.

150
Malfist

Cas d'utilisation:

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

Comme table inline évaluée UDF

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

Usage:

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

ADDENDUM: Ceci est probablement préférable pour ne traiter que deux valeurs possibles. S'il y en a plus de deux, considérez réponse de Craig en utilisant la clause Values.

112
Charles Bretana

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

SELECT IIF(first>second, second, first) the_minimal FROM table

Bien que IIF ne soit qu'un raccourci pour écrire CASE...WHEN...ELSE, il est plus facile d’écrire.

115
Mert Gülsoy

Les solutions utilisant CASE, IIF et UDF sont adéquates, mais peu pratiques pour étendre le problème au cas général en utilisant plus de 2 valeurs de comparaison. La solution généralisée de SQL Server 2008+ utilise une application étrange de la clause VALUES:

SELECT
PaidForPast=(SELECT MIN(x) FROM (VALUES (PaidThisMonth),(OwedPast)) AS value(x))

Crédit dû à ce site web: http://sqlblog.com/blogs/jamie_thomson/archive/2012/01/20/use-values-clause-to-get-the-max-une-valeur-de-some- Colonnes-sql-serveur-t-sql.aspx

90
Craig

Je viens d'avoir une situation où je devais trouver le maximum de 4 sélections complexes dans une mise à jour. Avec cette approche, vous pouvez en avoir autant que vous voulez!

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.

28
MartinC

Pour MySQL ou PostgreSQL, un meilleur moyen consiste à utiliser les fonctions LEAST et GREATEST.

SELECT GREATEST(A.date0, B.date0) AS date0, 
       LEAST(A.date1, B.date1, B.date2) AS date1
FROM A, B
WHERE B.x = A.x

Les deux sont décrits ici: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html

16
Gil Margolin

Voici une astuce si vous voulez calculer le maximum (champ, 0):

SELECT (ABS(field) + field)/2 FROM Table

renvoie 0 si field est négatif, sinon renvoie field.

12
mathematix

Utilisez une instruction 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, 'Price Range' = 
      CASE 
         WHEN ListPrice =  0 THEN 'Mfg item - not for resale'
         WHEN ListPrice < 50 THEN 'Under $50'
         WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'
         WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'
         ELSE 'Over $1000'
      END
FROM Production.Product
ORDER BY ProductNumber ;
GO
5
Mike Cole

Cela fonctionne pour un maximum de 5 dates et gère les valeurs nulles. Je ne pouvais tout simplement pas 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
--USAGE 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
2
Lawrence

Utilisez une table temp pour insérer la plage de valeurs, puis sélectionnez les valeurs min/max de la table temp dans une procédure stockée ou un fichier UDF. Ceci est une construction de base, alors n'hésitez pas à réviser au besoin.

Par exemple:

CREATE PROCEDURE GetMinSpeed() AS
BEGIN

    CREATE TABLE #speed (Driver NVARCHAR(10), SPEED INT);
    '
    ' Insert any number of data you need to sort and pull from
    '
    INSERT INTO #speed (N'Petty', 165)
    INSERT INTO #speed (N'Earnhardt', 172)
    INSERT INTO #speed (N'Patrick', 174)

    SELECT MIN(SPEED) FROM #speed

    DROP TABLE #speed

END
2
user1970604

En me basant sur la brillante logique/code de mathematix et scottyc, je soumets:

DECLARE @a INT, @b INT, @c INT = 0

WHILE @c < 100
    BEGIN
        SET @c += 1
        SET @a = ROUND(Rand()*100,0)-50
        SET @b = ROUND(Rand()*100,0)-50
        SELECT @a AS a, @b AS b,
            @a - ( ABS(@a-@b) + (@a-@b) ) / 2 AS MINab,
            @a + ( ABS(@b-@a) + (@b-@a) ) / 2 AS MAXab,
            CASE WHEN (@a <= @b AND @a = @a - ( ABS(@a-@b) + (@a-@b) ) / 2)
            OR (@a >= @b AND @a = @a + ( ABS(@b-@a) + (@b-@a) ) / 2)
            THEN 'Success' ELSE 'Failure' END AS Status
    END

Bien que le saut de la fonction MIN de scottyc à la fonction MAX aurait dû être évident pour moi, ce n’était pas le cas, j’ai donc résolu le problème et l’inclus ici: SELECT @a + (ABS (@ b- @ a) + ( @ b- @ a))/2. Les nombres générés aléatoirement, sans être une preuve, devraient au moins convaincre les sceptiques que les deux formules sont correctes.

2
DaveX