En révisant cette question il semble que ce soit beaucoup de travail qui ne devrait pas être nécessaire. Ils essaient d'étendre une plage avec une date. Dans d'autres bases de données, vous utiliseriez simplement greatest
et least
..
least(extendDate,min), greatest(extendDate,max)
Quand j'essaie de les utiliser, je reçois
'least' is not a recognized built-in function name.
'greatest' is not a recognized built-in function name.
Cela couvrirait l'extension dans les deux sens.
Aux fins de la question, vous devrez toujours effectuer un remplacement de gamme exclusif.
Je me demande simplement comment les utilisateurs de SQL Server implémentent des modèles de requête pour imiter les fonctionnalités least
et greatest
.
GREATEST
/LEAST
GREATEST
/LEAST
GREATEST
LEAST
GREATEST
LEAST
GREATEST
LEAST
Déroulez-vous les conditions dans les instructions CASE
ou existe-t-il une extension, un module complémentaire tiers ou une licence de Microsoft qui active cette fonctionnalité?
Une méthode courante consiste à utiliser la clause VALUES
et CROSS APPLY
les deux colonnes aliasées en une seule colonne, puis obtenez les MIN
et MAX
de chacune.
SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM dbo.Users AS u
CROSS APPLY ( VALUES ( u.CreationDate ), ( u.LastAccessDate )) AS x ( CombinedDate );
Il existe d'autres façons de l'écrire, par exemple en utilisant UNION ALL
SELECT MIN(x.CombinedDate) AS least, MAX(x.CombinedDate) AS greatest
FROM dbo.Users AS u
CROSS APPLY ( SELECT u.CreationDate UNION ALL SELECT u.LastAccessDate ) AS x(CombinedDate);
Cependant, le résultat plans de requête semble être le même.
Vous pouvez également mettre les valeurs en ligne dans une sous-requête. Comme ça:
select (select max(i) from (values (1), (2), (5), (1), (6)) AS T(i)) greatest,
(select min(i) from (values (1), (2), (5), (1), (6)) AS T(i)) least
MOINS équivalent:
IIF(@a < @b, @a, @b)
LE PLUS GRAND équivalent:
IIF(@a > @b, @a, @b)
Ce serait un bon début -
CASE WHEN A > B THEN A ELSE B END
Je crée des fonctions définies par l'utilisateur, par ex.
create function dbo.udf_LeastInt(@a int, @b int)
returns int
with schemabinding
as
begin
return case when @a <= @b then @a
when @b < @a then @b
else null
end
end
Bien qu'elle puisse fonctionner dans des cas simples, cette approche présente cependant plusieurs problèmes:
least
dans Oracle et MySQL, mais diffère de Postgres. Mais ce blindage contre null le rend plus verbeux (si vous savez qu'ils ne seront pas nuls, un simple case when @a <= @b then @a else @b end
travaillerait).Dans l'ensemble, il peut être préférable d'écrire la déclaration case
à la main si les performances sont importantes. J'ai même eu recours à la génération d'instructions case
imbriquées côté client lorsqu'il y a plusieurs valeurs à comparer.
J'avais l'intention d'ajouter un commentaire à la réponse @ ed-avis, mais je ne pouvais pas le faire, en raison du manque de réputation, alors je poste ceci en tant qu'extension à sa réponse.
J'ai éliminé l'inconvénient de "De façon ennuyeuse, vous devez créer des fonctions distinctes pour chaque type de données." Utilisation de SQL_VARIANT .
Voici ma mise en œuvre:
CREATE OR ALTER FUNCTION my_least(@a SQL_VARIANT, @b SQL_VARIANT)
returns SQL_VARIANT
with schemabinding
as
begin
return case when @a <= @b then @a
when @b < @a then @b
WHEN @a IS NULL THEN @b
WHEN @b IS NULL THEN @a
else null
end
END;
De plus, cette fonction gère [~ # ~] null [~ # ~] comme la version postgresql.
Cette fonction pourrait être ajoutée à la base de données pour plus de commodité, mais elle est 10 fois plus lente que l'utilisation de IIF
intégré. Mes tests montrent que cette fonction de type exact ( datetime ) fonctionne de la même manière que sql_variant version.
PS Je lance des tests sur un ensemble de données de 350k valeurs, et il semble que les performances soient les mêmes, sql_variant est un peu plus rapide, mais je crois que ce n'est que de la frousse.
Mais de toute façon la version IIF est 10x fois plus rapide !!!
Je n'ai pas testé en ligne CASE WHEN
mais essentiellement pour t-sql IIF est identique à case , et iif get est converti par l'optimiseur en expression case.
Le fait que l'IIF soit traduit en CASE a également un impact sur d'autres aspects du comportement de cette fonction.
CONCLUSION: Son utilisation est plus rapide [~ # ~] iif [~ # ~] si les performances sont importantes, mais pour le prototypage, ou si la clarté du code est plus nécessaire, et qu'aucun gros calcul n'est impliqué, à condition que la fonction puisse être utilisée.