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

问题描述 投票:457回答:29

我想写这样的查询:

SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o

但是这不是MAX函数的工作原理,对吗?它是一个聚合函数,因此需要一个参数,然后返回所有行的MAX。

有人知道我该怎么做吗?

sql sql-server max
29个回答
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

...,您会这样称呼它...

SELECT o.OrderId, dbo.InlineMax(o.NegotiatedPrice, o.SuggestedPrice) 
FROM Order o

5
投票

我会采用false_value提供的解决方案只需稍加修改即可处理NULL

NULL

编辑kcrumley中添加注释后进行了修改。正如他在3个值逻辑中正确指出的那样,x> NULL或x


4
投票

就这么简单:

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

3
投票

糟糕,我刚刚发布了Mark ...

答案是,没有像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; 这样的内置函数,但是对于使用UDF的2列,您可以实现类似的结果,请注意,此处使用sql_variant非常重要。

dupe of this question

Oracle's Greatest

发布此答案:

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

3
投票

这是一个应该处理null并与旧版本的MSSQL一起使用的案例。这基于流行示例之一中的内联函数:

kristof

3
投票

在SQL Server 2012或更高版本中,可以组合使用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 case when a >= b then a else isnull(b,a) end (或IIF)来获取最多2个值。即使其中之一为NULL。

ISNULL

或如果它们都为NULL时希望它返回0

COALESCE

示例代码段:

IIF(col1 >= col2, col1, ISNULL(col2, col1)) 

结果:

IIF(col1 >= col2, col1, COALESCE(col2, col1, 0)) 

2
投票

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

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

2
投票

对于以上有关大数的答案,您可以在加法/减法之前进行乘法。它有点笨重,但不需要演员。 (我不能代表速度,但我认为它仍然相当快)

选择0.5 *((@ val1 + @ val2)+ABS(@ val1-@ val2))

更改为

SELECT @ val1 * 0.5 + @ val2 * 0.5 +ABS(@ val1 * 0.5-@ val2 * 0.5)

至少是一种避免铸造的替代方法。


2
投票

这里是具有NULL处理的IIF版本(基于Xin的回答:]

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

逻辑如下,如果两个值中的任何一个为NULL,则返回不为NULL的值(如果两个均为NULL,则返回NULL)。否则返回更大的一个。

MIN可以做同样的事情。

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

2
投票
IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a > b, a, b))

1
投票

您可以执行以下操作:

IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a < b, a, b))

437
投票

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

SELECT o.OrderId,
       (SELECT MAX(Price)
        FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o

[所有功劳和投票应归Sven's answer to a related question, "SQL MAX of multiple columns?"我说它是“ 最佳答案”,因为:

  1. 它不需要将代码与UNION,PIVOT和UNPIVOT,UDF和疯狂的CASE语句。
  2. 它不存在处理null的问题,它可以很好地处理它们。
  3. 很容易将“ MAX”替换为“ MIN”,“ AVG”或“ SUM”。您可以使用任何聚合函数来查找许多不同列上的聚合。
  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
投票
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

1
投票
select case when o.NegotiatedPrice > o.SuggestedPrice 
then o.NegotiatedPrice
else o.SuggestedPrice
end

1
投票

以最简单的形式...

SELECT o.OrderID
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN
 o.NegotiatedPrice
ELSE
 o.SuggestedPrice
END AS Price

1
投票

对于SQL Server 2012:

CREATE FUNCTION [dbo].[fnMax] (@p1 INT, @p2 INT)
RETURNS INT
AS BEGIN

    DECLARE @Result INT

    SET @p2 = COALESCE(@p2, @p1)

    SELECT
        @Result = (
                   SELECT
                    CASE WHEN @p1 > @p2 THEN @p1
                         ELSE @p2
                    END
                  )

    RETURN @Result

END

1
投票

这里是@Scott Langham的答案,其中包含简单的NULL处理:

CREATE FUNCTION fnGreatestInt (@Int1 int, @Int2 int )
RETURNS int
AS
BEGIN

    IF @Int1 >= ISNULL(@Int2,@Int1)
        RETURN @Int1
    ELSE
        RETURN @Int2

    RETURN NULL --Never Hit

END

0
投票
SELECT 
    o.OrderId, 
    IIF( o.NegotiatedPrice >= o.SuggestedPrice,
         o.NegotiatedPrice, 
         ISNULL(o.SuggestedPrice, o.NegiatedPrice) 
    )
FROM 
    Order o

0
投票
SELECT
      o.OrderId,
      CASE WHEN (o.NegotiatedPrice > o.SuggestedPrice OR o.SuggestedPrice IS NULL) 
         THEN o.NegotiatedPrice 
         ELSE o.SuggestedPrice
      END As MaxPrice
FROM Order o

0
投票

扩展Xin的答案并假设比较值类型为INT,这种方法也适用:

select OrderId, (
    select max([Price]) from (
        select NegotiatedPrice [Price]
        union all
        select SuggestedPrice
    ) p
) from [Order]

这是带有示例值的完整测试:

 -- Simple way without "functions" or "IF" or "CASE"
 -- Query to select maximum value
 SELECT o.OrderId
  ,(SELECT MAX(v)
   FROM (VALUES (o.NegotiatedPrice), (o.SuggestedPrice)) AS value(v)) AS MaxValue
  FROM Order o;

0
投票

在MemSQL中执行以下操作:

SELECT IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)

-1
投票

在您可以使用的前提下使用

DECLARE @A AS INT
DECLARE @B AS INT

SELECT  @A = 2, @B = 1
SELECT  IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)
-- 2

SELECT  @A = 2, @B = 3
SELECT  IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)
-- 3

SELECT  @A = 2, @B = NULL
SELECT  IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)
-- 2    

SELECT  @A = NULL, @B = 1
SELECT  IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)
-- 1

216
投票

可以在一行中完成:

-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2)) 

Edit: 如果要处理非常大的数字,则必须将值变量转换为bigint,以避免整数溢出。


124
投票

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

SELECT
  o.OrderId,
  CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice 
     ELSE o.SuggestedPrice
  END
FROM Order o

76
投票

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

IIF(a>b, a, b)

就是这样。

(提示:请注意,其中一个都为null,因为只要其中一个为空,a>b的结果都将为false。因此,在这种情况下,b将为结果)]


32
投票
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)

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

8
投票

子查询可以访问外部查询中的列,因此您可以使用this approach跨列使用聚合,例如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

6
投票

SQL Server 2012引入的IIF

IIF

使用NULL时,建议使用NULL处理,因为在SELECT o.OrderId, IIF( ISNULL( o.NegotiatedPrice, 0 ) > ISNULL( o.SuggestedPrice, 0 ), o.NegotiatedPrice, o.SuggestedPrice ) FROM Order o 两侧的IIF会导致NULL返回boolean_expression(与IIF相反)。

© www.soinside.com 2019 - 2024. All rights reserved.