SQL Server是否支持GREATEST和LEAST,如果不是,通常的解决方法是什么?


20

回顾这个问题,似乎不需要做很多工作。他们正在尝试扩大日期范围。在其他数据库中,您只需使用greatestleast..

least(extendDate,min), greatest(extendDate,max)

当我尝试使用这些时,我得到

'least' is not a recognized built-in function name.
'greatest' is not a recognized built-in function name.

那将覆盖任一方向的延伸。

出于问题的目的,您仍然必须进行排他性范围替换。

我只是想知道SQL Server用户如何实现查询模式来模仿leastgreatest功能化。

您是否将条件展开为CASE语句,或者是否有Microsoft的扩展程序,第三方加载项或许可证来启用此功能?


Answers:


33

一种常见的方法是使用该VALUES子句,并将CROSS APPLY两列别名为一个列,然后获取每个的MINMAX

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 );

还有其他编写方式,例如使用 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);

但是,生成的查询计划似乎是相同的。


14

您还可以将值内联到子查询中。像这样:

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


3

至少等效:

IIF(@a < @b, @a, @b)

相当于最大

IIF(@a > @b, @a, @b)

3
例如,对于三个或三个以上的值,您该怎么做least(5,6,7,8,9)
a_horse_with_no_name

@a_horse_with_no_name使用嵌套的IIF
Elnur

这种方法将很快变得难以阅读和验证...就性能而言,它的表现如何?
Dodecaphone

0

我创建用户定义的函数,例如

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

尽管它可能在简单的情况下可行,但是这种方法存在一些问题:

  • 烦人的是,您必须为每种数据类型分别创建函数。
  • 它仅处理2个参数,因此可能需要更多函数来处理许多参数或使用同一函数的嵌套调用。
  • 作为内联TVF而不是标量函数会更好(更有效率)。这与本质上实现标量函数有关。关于它的博客很多,例如,参见《SQL 101:并行性抑制剂–标量用户定义函数》(作者:John Kehayias)
  • 如果参数之一为null,则返回null。这与least运算符在Oracle和MySQL中的操作匹配,但不同于Postgres。但是这种针对null的防护使它变得更加冗长(如果您知道它们不会为null,那么简单case when @a <= @b then @a else @b end就可以了)。

总而言之,case如果性能很重要,最好长期写出该语句。case当有多个要比较的值时,我什至诉诸于在客户端生成嵌套语句。


0

我本打算在@ ed-avis答案中添加评论,但由于缺乏声誉而无法添加评论,因此将其发布为他的答案的扩展。

我消除了“令人讨厌的是,您必须为每种数据类型分别创建函数”的缺点。使用SQL_VARIANT

这是我的实现:

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;

此函数也处理NULL,如postgresql版本。

为了方便起见,可以将此功能添加到数据库中,但比使用内置功能慢10倍IIF。我的测试表明,具有确切类型(datetime)的此类函数执行与sql_variant版本相同的功能。

PS 我对350k值的数据集进行了一些测试,似乎性能是相同的,sql_variant稍快一些,但我认为这只是抖动。

但是无论如何,IIF版本都快10倍!!!

我还没有进行内联测试,CASE WHEN但基本上对于t-sql IIF与case相同,并且iif get由优化器转换为case表达式。

将IIF转换为CASE的事实也对该功能行为的其他方面产生影响。

结论:如果性能很重要,则使用IIF更快,但是对于原型设计,或者如果更需要代码清晰度,并且不涉及大量计算,则可以使用功能。


当SQL方言中存在LEAST()和GREATEST()时,允许在n列之间的一行内进行比较;我将OP视为追求可提供等效结果的解决方案。这里的答案(以及其他几个答案)仅支持
2。– Dodecaphone
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.