我想写一个这样的查询:

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

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

有人知道我的方法吗?


当前回答

在SQL Server 2012或更高版本中,您可以使用IIF和ISNULL(或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

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

其他回答

以下是一个带有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))

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

最简单的形式是……

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

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

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

哎呀,我刚刚发布了一个关于这个问题的恶搞帖…

答案是,没有像Oracle's Greatest这样的内置函数,但是您可以通过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

克里斯汀

下面是我的回答:

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