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.
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.
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.
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
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.
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
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
.
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
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
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
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.