Есть ли в SQL Server функция Max, которая принимает два значения, такие как Math.Max ​​в .NET? - PullRequest
434 голосов
/ 24 сентября 2008

Я хочу написать запрос, подобный этому:

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

Но это не так, как работает функция MAX, верно? Это агрегатная функция, поэтому она ожидает один параметр, а затем возвращает MAX всех строк.

Кто-нибудь знает, как это сделать по-моему?

Ответы [ 28 ]

4 голосов
/ 24 февраля 2014

Это так просто:

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;
3 голосов
/ 24 октября 2016

Вот пример случая, который должен обрабатывать нули и работать с более старыми версиями MSSQL. Это основано на встроенной функции в одном из популярных примеров:

case
  when a >= b then a
  else isnull(b,a)
end
3 голосов
/ 13 октября 2008

Ой, я только что опубликовал дубли этого вопроса ...

Ответ таков: нет встроенной функции, такой как Oracle Greatest , но вы можете достичь аналогичного результата для 2 столбцов с 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
2 голосов
/ 24 сентября 2008

Я, вероятно, не стал бы делать это так, поскольку он менее эффективен, чем уже упоминавшиеся конструкции 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
2 голосов
/ 06 сентября 2017

Вот версия IIF с обработкой NULL (на основе ответа 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))
2 голосов
/ 12 сентября 2018
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 голос
/ 14 февраля 2019

В SQL Server 2012 или более поздней версии вы можете использовать комбинацию IIF и ISNULL (или COALESCE), чтобы получить максимум 2 значения.
Даже когда 1 из них имеет значение NULL.

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

Или, если вы хотите, чтобы он возвращал 0, когда оба равны NULL

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
1 голос
/ 24 сентября 2008
SELECT o.OrderID
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN
 o.NegotiatedPrice
ELSE
 o.SuggestedPrice
END AS Price
1 голос
/ 07 июня 2010
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 голос
/ 07 декабря 2015

Для SQL Server 2012:

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