SQL Server中是否有一个Max函数,它在.NET中采用Math.Max这两个值?

skb*_*skb 457 sql sql-server max

我想写一个这样的查询:

SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
Run Code Online (Sandbox Code Playgroud)

但这不是这个MAX功能的工作方式,对吧?它是一个聚合函数,因此它需要一个参数,然后返回所有行的MAX.

有谁知道怎么做我的方式?

Mik*_*Vee 437

如果您使用的是SQL Server 2008(或更高版本),那么这是更好的解决方案:

SELECT o.OrderId,
       (SELECT MAX(Price)
        FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o
Run Code Online (Sandbox Code Playgroud)

所有的信用和投票应该转到Sven对相关问题的回答,"多列的SQL MAX?"
我说这是" 最佳答案 ",因为:

  1. 它不需要使用UNION,PIVOT,UNPIVOT,UDF和疯狂的CASE语句使您的代码复杂化.
  2. 它没有处理空值的问题,它处理它们就好了.
  3. 用"MIN","AVG"或"SUM"换出"MAX"很容易.您可以使用任何聚合函数来查找许多不同列上的聚合.
  4. 您不仅限于我使用的名称(即"AllPrices"和"Price").您可以选择自己的名字,以便下一个人更容易阅读和理解.
  5. 您可以使用SQL Server 2008的derived_tables找到多个聚合,如下所示:
    SELECT MAX(a),MAX(b)FROM(VALUES(1,2),(3,4),(5,6),(7,8), (9,10))AS MyTable(a,b)

  • 仅+1回答不需要访问创建过程/功能! (24认同)
  • 这比仅需要计算标量的CASE WHEN解决方案性能更差. (10认同)
  • 正是我想要的答案类型.使用函数很慢,这也适用于日期,这是我需要的. (6认同)
  • 虽然在确定2个值的MAX时,更简单的语法可能永远不值得性能损失,但是具有更多值的情况可能是不同的.即使获得4个值的MAX,CASE条款也会变得冗长,笨拙且容易出错,而VALUES条款仍然简单明了. (4认同)
  • +1完美无缺,特别适合超过2列进行比较! (3认同)
  • 需要注意的是 - 我在 SET x = (SELECT MAX(CopyCount) FROM (VALUES (x - 1),(0)) AS Copies(CopyCount)) 形式的 UPDATE 语句中使用了它,它的性能非常糟糕,并且偶尔会导致给我错误,数据库无法再更新该行。 (2认同)

spl*_*tne 216

可以在一行中完成:

-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2)) 
Run Code Online (Sandbox Code Playgroud)

编辑: 如果你处理非常大的数字,你必须将值变量转换为bigint,以避免整数溢出.

  • 这是非常"肮脏"的"诡计".编程代码时应明确表达目标,但在您的情况下,它看起来像是从混淆竞赛中获取的代码. (84认同)
  • 它可能是"脏的",但它可能是具有简单SQL方言的数据库的唯一选择. (24认同)
  • +1我相信你提供了最正确的方法."SELECT((@ val1 + @ val2)+ ABS(@ val1- @ val2))/ 2为MAX_OF_TWO"还要记住,"SELECT((@ val1 + @ val2) - ABS(@ val1- @ val2))/ 2为MIN_OF_TWO ". (17认同)
  • 我不同意marcias.代码本身不一定需要明确表达目标,只要注释允许人们解决它.如果你在代码(或任何地方)中进行任何复杂的数学方程式,有时很难让它自我描述.只要将其分解为更简单,更易于理解的部分,那就是正确的编程. (12认同)
  • 如果总和大于可以存储在int中,则这种方式会产生溢出错误:declare @ val1 int declare @ val2 int set @ val1 = 1500000000 set @ val2 = 1500000000 SELECT 0.5*((@ val1 + @ val2)+ ABS(@ val1 - @ val2)) - =>溢出错误 (6认同)
  • 我以前从未见过这个.天才. (6认同)
  • 因为它不是立即显而易见的,所以这是有效的,因为`ABS`表达式计算最小值和最大值之间差异的大小.将其重新添加到最小值和最大值的总和使得总和是最大值的两倍(总是可以被2整除).除以2将返回最大值.我相信你可以通过减去`ABS`表达而不是添加来改变它来实现'MIN`的功能. (6认同)
  • 旧线程我知道,但这适用于日期(它使用上面的公式):`dateadd(dd,((datediff(dd,0,[Date1])+ datediff(dd,0,[Date2]))+ abs(datediff) (dd,0,[Date1]) - datediff(dd,0,[Date2])))/ 2,0) (4认同)
  • 整齐的数学技巧,但我畏惧做浮点运算以获得最多两个整数的想法. (3认同)
  • 使用浮点类型时精度损失意味着您可能无法获得实际的最大值,只能获得一个非常接近的数字。 (3认同)
  • @King,它不是浮点数,如果用`div 2`替换`*0.5`,它再次是整数数学.这在其他代码中也会非常好用,因为你避免了if-then跳转,从而避免了分支错误预测(显然是以更长的关键路径为代价). (2认同)
  • 这适用于整数等,但不适用于其他数据类型,例如日期时间(这是我的特定用例 - 在结果集中构造一个列,该列的每一行都具有两个日期列中的最大值(即最新的) )。 (2认同)
  • 太酷了!! 但case语句读起来更好。 (2认同)
  • 如果任一值为空,您将获得空值。可能不是想要的。 (2认同)
  • 有人制定了[证据](https://math.stackexchange.com/a/429630)♥ (2认同)

Kev*_*ley 151

你需要制作一个User-Defined Function如果你想要的语法类似于你的例子,但是你可以CASE像其他人所说的那样,用一个语句来内联,相当容易地做你想做的事情.

UDF会是这样的:

create function dbo.InlineMax(@val1 int, @val2 int)
returns int
as
begin
  if @val1 > @val2
    return @val1
  return isnull(@val2,@val1)
end
Run Code Online (Sandbox Code Playgroud)

......你会这样称呼它......

SELECT o.OrderId, dbo.InlineMax(o.NegotiatedPrice, o.SuggestedPrice) 
FROM Order o
Run Code Online (Sandbox Code Playgroud)

  • 我会支持你的解决方案,我唯一要补充的是对NULL值的支持.如果你只修改最后一行:"return @ value2"读作:"return isnull(@ val2,@ val1)"然后如果其中一个值为null,则函数将返回not null值,否则它将作为正常 (22认同)
  • @Thomas强制性模因形象(不以任何方式对你有任何冒犯!)http://www.flickr.com/photos/16201371@N00/2375571206/ (12认同)
  • @xan当我真正提出这个问题时,我无法理解我的想法.显然不是太多.无论如何,谢谢你的回答. (11认同)
  • 这将是非常缓慢的,因为所有东西都是标量UDF.请改用内联UDF (9认同)
  • 其他数据类型怎么样,例如我需要编写一个 HigherIntegerArgument 和一个 HigherDateTimeArgument 和一个 HigherVarcharArgument 和一个......? (2认同)

Sco*_*ham 124

我不这么认为.前几天我想要这个.我得到的最接近的是:

SELECT
  o.OrderId,
  CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice 
     ELSE o.SuggestedPrice
  END
FROM Order o
Run Code Online (Sandbox Code Playgroud)

  • +1用于直接解决方案,但您不处理空值. (9认同)
  • 这是我最喜欢的方法.你没有冒出溢出的风险,并且它比splattne的解决方案(这很酷)没有那么神秘,而且我没有创建UDF的麻烦.在许多情况下,案例非常方便. (4认同)

Xin*_*Xin 76

为什么不尝试IIF功能(需要SQL Server 2012及更高版本)

IIF(a>b, a, b)
Run Code Online (Sandbox Code Playgroud)

而已.

(提示:要么小心null,因为a>b只要其中任何一个为null ,结果都将为false.因此b,在这种情况下将是结果)

  • 如果其中一个值为"NULL",则结果将始终为第二个. (5认同)
  • IIF()是CASE语句的语法糖。如果CASE条件的任何一个值为NULL,则结果将是第二个(ELSE)。 (3认同)
  • 所以`IIF(a> b,a,COALESCE(b,a))`给出只有一个存在时的值 (2认同)

jbe*_*nky 32

DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)
Run Code Online (Sandbox Code Playgroud)

  • 我讨厌我不得不求助于这个解决方案,但它肯定是在 SQL Server 中做到这一点的最佳方式,直到他们添加对 GREATEST 或内联 MAX 的本机支持。感谢您发布它 - 给您 +1! (2认同)

Luk*_*zda 26

就在这里。

T-SQL (SQL Server 2022 (16.x)) 现在支持 GREATEST/LEAST 函数:

MAX/MIN 作为非聚合函数

此功能现已适用于 Azure SQL 数据库和 SQL 托管实例。它将进入下一版本的 SQL Server。


逻辑函数 - GREATEST (Transact-SQL)

此函数返回一个或多个表达式列表中的最大值。

GREATEST ( expression1 [ ,...expressionN ] ) 
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下:

SELECT o.OrderId, GREATEST(o.NegotiatedPrice, o.SuggestedPrice)
FROM [Order] o;
Run Code Online (Sandbox Code Playgroud)

db<>小提琴演示

  • 您**不会**在 SQL Server 2019 (150) 或更早版本上找到这些函数。 (9认同)

Luk*_*rms 18

在 SQL Server 2012 或更高版本中,您可以使用IIFISNULL(或COALESCE)的组合来获取最多 2 个值。
即使其中 1 个为 NULL。

IIF(col1 >= col2, col1, ISNULL(col2, col1)) 
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望它在两者都为 NULL 时返回 0

IIF(col1 >= col2, col1, COALESCE(col2, col1, 0)) 
Run Code Online (Sandbox Code Playgroud)

示例片段:

-- use table variable for testing purposes
declare @Order table 
(
  OrderId int primary key identity(1,1),
  NegotiatedPrice decimal(10,2),
  SuggestedPrice decimal(10,2)
);

-- Sample data
insert into @Order (NegotiatedPrice, SuggestedPrice) values
(0, 1),
(2, 1),
(3, null),
(null, 4);

-- Query
SELECT 
     o.OrderId, o.NegotiatedPrice, o.SuggestedPrice, 
     IIF(o.NegotiatedPrice >= o.SuggestedPrice, o.NegotiatedPrice, ISNULL(o.SuggestedPrice, o.NegotiatedPrice)) AS MaxPrice
FROM @Order o
Run Code Online (Sandbox Code Playgroud)

结果:

OrderId NegotiatedPrice SuggestedPrice  MaxPrice
1       0,00            1,00            1,00
2       2,00            1,00            2,00
3       3,00            NULL            3,00
4       NULL            4,00            4,00
Run Code Online (Sandbox Code Playgroud)

但是,如果需要最多的多列呢?
然后我建议对 VALUES 的聚合进行 CROSS APPLY。

例子:

SELECT t.*
, ca.[Maximum]
, ca.[Minimum], ca.[Total], ca.[Average]
FROM SomeTable t
CROSS APPLY (
   SELECT 
    MAX(v.col) AS [Maximum], 
    MIN(v.col) AS [Minimum], 
    SUM(v.col) AS [Total], 
    AVG(v.col) AS [Average]
   FROM (VALUES (t.Col1), (t.Col2), (t.Col3), (t.Col4)) v(col)
) ca
Run Code Online (Sandbox Code Playgroud)

这有一个额外的好处,它可以同时计算其他东西。


小智 10

其他答案都很好,但如果你不得不担心有NULL值,你可能想要这个变种:

SELECT o.OrderId, 
   CASE WHEN ISNULL(o.NegotiatedPrice, o.SuggestedPrice) > ISNULL(o.SuggestedPrice, o.NegotiatedPrice)
        THEN ISNULL(o.NegotiatedPrice, o.SuggestedPrice)
        ELSE ISNULL(o.SuggestedPrice, o.NegotiatedPrice)
   END
FROM Order o
Run Code Online (Sandbox Code Playgroud)

  • 唯一需要的 ISNULL 位于 ELSE 之后。如果其中一个值已经为 null,则初始 "&gt;" 比较将返回 false 并转到 ELSE。 (2认同)

Mar*_*ith 8

子查询可以访问外部查询中的列,因此您可以使用此方法来使用聚合,例如MAX跨列.(当涉及更多列时,可能更有用)

;WITH [Order] AS
(
SELECT 1 AS OrderId, 100 AS NegotiatedPrice, 110 AS SuggestedPrice UNION ALL
SELECT 2 AS OrderId, 1000 AS NegotiatedPrice, 50 AS SuggestedPrice
)
SELECT
       o.OrderId, 
       (SELECT MAX(price)FROM 
           (SELECT o.NegotiatedPrice AS price 
            UNION ALL SELECT o.SuggestedPrice) d) 
        AS MaxPrice 
FROM  [Order]  o
Run Code Online (Sandbox Code Playgroud)


小智 7

SELECT o.OrderId,   
--MAX(o.NegotiatedPrice, o.SuggestedPrice)  
(SELECT MAX(v) FROM (VALUES (o.NegotiatedPrice), (o.SuggestedPrice)) AS value(v)) as ChoosenPrice  
FROM Order o
Run Code Online (Sandbox Code Playgroud)

  • 请不要仅通过链接将所需信息包含到您的代码中。想象一下,这个链接有一天会过期,然后你的回答就没有用了。因此,请继续并直接在您的答案中添加 essentiell 信息。但是您仍然可以提供该链接作为其他人查找更多信息的资源。 (4认同)

Set*_*uth 6

SQL Server 2012介绍IIF:

SELECT 
    o.OrderId, 
    IIF( ISNULL( o.NegotiatedPrice, 0 ) > ISNULL( o.SuggestedPrice, 0 ),
         o.NegotiatedPrice, 
         o.SuggestedPrice 
    )
FROM 
    Order o
Run Code Online (Sandbox Code Playgroud)

在使用时建议处理NULL IIF,因为NULL在你的任何一方boolean_expression都会导致IIF返回false_value(而不是NULL).


Mar*_*ett 5

我可能不会这样做,因为它比已经提到的 CASE 构造效率低 - 除非您可能覆盖两个查询的索引。无论哪种方式,对于类似的问题来说,这都是一种有用的技术:

SELECT OrderId, MAX(Price) as Price FROM (
   SELECT o.OrderId, o.NegotiatedPrice as Price FROM Order o
   UNION ALL
   SELECT o.OrderId, o.SuggestedPrice as Price FROM Order o
) as A
GROUP BY OrderId
Run Code Online (Sandbox Code Playgroud)


kri*_*tof 5

我会使用kcrumley提供的解决方案 只需稍微修改它来处理NULL

create function dbo.HigherArgumentOrNull(@val1 int, @val2 int)
returns int
as
begin
  if @val1 >= @val2
    return @val1
  if @val1 < @val2
    return @val2

 return NULL
end
Run Code Online (Sandbox Code Playgroud)

编辑 从评论后修改马克.正如他在3值逻辑中正确指出的那样x> NULL或x <NULL应始终返回NULL.换句话说,未知的结果.

  • 这将非常缓慢,因为所有的东西都是标量 UDF。改用内联 UDF (3认同)
  • 空值很重要。始终如一地处理它们很重要。Is NULL &gt; x 的唯一正确答案是 NULL。 (2认同)

Sam*_*ron 5

哎呀,我刚刚发布了这个问题的一个骗局......

答案是,没有像Oracle 的 Greatest这样的内置函数,但是您可以使用 UDF 对 2 列实现类似的结果,注意,sql_variant 的使用在这里非常重要。

create table #t (a int, b int) 

insert #t
select 1,2 union all 
select 3,4 union all
select 5,2

-- option 1 - A case statement
select case when a > b then a else b end
from #t

-- option 2 - A union statement 
select a from #t where a >= b 
union all 
select b from #t where b > a 

-- option 3 - A udf
create function dbo.GREATEST
( 
    @a as sql_variant,
    @b as sql_variant
)
returns sql_variant
begin   
    declare @max sql_variant 
    if @a is null or @b is null return null
    if @b > @a return @b  
    return @a 
end


select dbo.GREATEST(a,b)
from #t
Run Code Online (Sandbox Code Playgroud)

克里斯托夫

发布了这个答案:

create table #t (id int IDENTITY(1,1), a int, b int)
insert #t
select 1,2 union all
select 3,4 union all
select 5,2

select id, max(val)
from #t
    unpivot (val for col in (a, b)) as unpvt
group by id
Run Code Online (Sandbox Code Playgroud)

  • 使用 sql_variant 时应该小心。在以下情况下,您的函数将给出意外结果: SELECT dbo.greatest(CAST(0.5 AS FLOAT), 100) (3认同)
  • 注意:GREATEST 函数实现将匹配 2 个参数的 oracle 行为,如果任何参数为 null,它将返回 null (2认同)

Uri*_*son 5

就这么简单:

CREATE FUNCTION InlineMax
(
    @p1 sql_variant,
    @p2 sql_variant
)  RETURNS sql_variant
AS
BEGIN
    RETURN CASE 
        WHEN @p1 IS NULL AND @p2 IS NOT NULL THEN @p2 
        WHEN @p2 IS NULL AND @p1 IS NOT NULL THEN @p1
        WHEN @p1 > @p2 THEN @p1
        ELSE @p2 END
END;
Run Code Online (Sandbox Code Playgroud)


Chr*_*ers 5

尝试这个。它可以处理 2 个以上的值

SELECT Max(v) FROM (VALUES (1), (2), (3)) AS value(v)
Run Code Online (Sandbox Code Playgroud)