SQL Server中是否有Max函数,它像Math一样取两个值。。net中的Max ?

我想写一个这样的查询:

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

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

有人知道我的方法吗?

602545 次浏览

我不这么想。我那天想要这个。我最接近的说法是:

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

你可以这样做:

select case when o.NegotiatedPrice > o.SuggestedPrice
then o.NegotiatedPrice
else o.SuggestedPrice
end
SELECT o.OrderID
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN
o.NegotiatedPrice
ELSE
o.SuggestedPrice
END AS Price

我可能不会这样做,因为它比前面提到的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

如果您想拥有与您的示例相似的语法,则需要创建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

其他答案都很好,但如果你不得不担心有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

我会使用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

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

哎呀,我刚刚发布了一个在这个问题上

答案是,没有像甲骨文最伟大的这样的内置函数,但是您可以使用UDF为两个列实现类似的结果,注意,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

摩挲< a href = " https://stackoverflow.com/users/3241/kristof " > < / >

下面是我的回答:

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

可以在一行中完成:

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

# EYZ0 # EYZ1

DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE)
FROM (SELECT 1 AS VALUE UNION
SELECT 2 AS VALUE) AS T1)
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

对于上面关于大数字的答案,你可以在加减法之前做乘法。它有点笨重,但不需要石膏。(我不能说速度,但我认为它仍然非常快)

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

更改

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

如果你想避免强制转换,至少有一个替代方案。

子查询可以从外部查询访问列,因此您可以使用这种方法跨列使用聚合,例如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

最简单的形式是……

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

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

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

所有的信用和投票都应该去Sven对相关问题的回答,“多列的SQL MAX ?”
我说它是“最佳答案”,因为:

  1. 它不需要用UNION的,PIVOT的,
  2. . UNPIVOT, UDF,和长得离谱的CASE语句
  3. 它没有处理空值的问题,它处理空值很好。
  4. 很容易用“MIN”,“AVG”或“SUM”替换“MAX”。您可以使用任何聚合函数来查找许多不同列的聚合。
  5. 您不局限于我使用的名称(即。“AllPrices”和“Price”)。你可以选择自己的名字,让下一个男人更容易阅读和理解。
  6. 您可以使用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)

其实很简单:

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;

SQL Server 2012引入IIF:

SELECT
o.OrderId,
IIF( ISNULL( o.NegotiatedPrice, 0 ) > ISNULL( o.SuggestedPrice, 0 ),
o.NegotiatedPrice,
o.SuggestedPrice
)
FROM
Order o

建议在使用IIF时处理null,因为在boolean_expression两侧的NULL将导致IIF返回false_value(而不是NULL)。

对于SQL Server 2012:

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

为什么不尝试国际金融协会函数(需要SQL Server 2012及更高版本)

IIF(a>b, a, b)

就是这样。

(提示:要小心任何一个将是null,因为a>b的结果将为假,只要任何一个为空。因此,b将是在这种情况下的结果)

这里有一个案例示例,应该处理null,并将与旧版本的MSSQL一起工作。这是基于一个流行例子中的内联函数:

case
when a >= b then a
else isnull(b,a)
end

以下是@Scott Langham用简单的NULL处理给出的答案:

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

以下是一个带有NULL处理的IIF版本(基于Xin的回答):

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

逻辑如下,如果其中一个值为NULL,则返回非NULL的值(如果两个值都为NULL,则返回NULL)。否则返回较大的值。

MIN也是一样。

IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a < b, a, b))
select OrderId, (
select max([Price]) from (
select NegotiatedPrice [Price]
union all
select SuggestedPrice
) p
) from [Order]

在Presto你可以使用

SELECT array_max(ARRAY[o.NegotiatedPrice, o.SuggestedPrice])
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
 -- 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;

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

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

这是一个完整的测试示例值:

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
在SQL Server 2012或更高版本中,您可以使用IIFISNULL(或COALESCE)的组合来获得2个值的最大值。
即使其中一个为NULL。

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

或者当两者都为NULL时,希望它返回0

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

示例代码片段:

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

结果:

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

但如果需要多列的最大值?
然后我建议对值的聚合进行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

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

在MemSQL中执行以下操作:

-- DROP FUNCTION IF EXISTS InlineMax;
DELIMITER //
CREATE FUNCTION InlineMax(val1 INT, val2 INT) RETURNS INT AS
DECLARE
val3 INT = 0;
BEGIN
IF val1 > val2 THEN
RETURN val1;
ELSE
RETURN val2;
END IF;
END //
DELIMITER ;


SELECT InlineMax(1,2) as test;

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

SELECT Max(v) FROM (VALUES (1), (2), (3)) AS value(v)

是的,有。

T-SQL (SQL Server 2022 (16.x))现在支持最大/最小函数:

MAX/MIN as NON-aggregate function

现在Azure SQL数据库和SQL托管实例都支持这个功能。它将滚动到下一个版本的SQL Server。

逻辑函数- GREATEST (Transact-SQL) . sql (Transact-SQL

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

GREATEST ( expression1 [ ,...expressionN ] )

在这种情况下:

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