Есть ли функция Макс в SQL Server, которая принимает два значения, такие как Math.Max ​​в .NET?

Я хочу написать такой запрос:

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

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

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

Ответ 1

Вам нужно будет сделать User-Defined Function, если вы хотите иметь синтаксис, похожий на ваш пример, но можете ли вы делать то, что хотите, inline, довольно легко с помощью инструкции 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

Ответ 2

Если вы используете SQL Server 2008 (или выше), это лучшее решение:

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

Все кредиты и голоса должны отправляться в Sven ответ на соответствующий вопрос: "SQL MAX из нескольких столбцов?"
Я говорю это" лучший ответ", потому что:

  • Это не требует усложнения вашего кода с помощью UNION, PIVOT, UNPIVOT, UDF и сумасшедшие статуты CASE.
  • Это не проблема с обработкой нулей, она отлично справляется с ними.
  • Легко поменять "MAX" на "MIN", "AVG" или "SUM". Вы можете использовать любую агрегированную функцию для поиска совокупности по многим различным столбцам.
  • Вы не ограничены именами, которые я использовал (т.е. "AllPrices" и "Price" ). Вы можете выбрать свои имена, чтобы облегчить чтение и понимание для следующего парня.
  • Вы можете найти несколько агрегатов, используя SQL Server 2008 производные_таблицы следующим образом:
    SELECT MAX (a), MAX (b) FROM (3, 4), (5, 6), (7, 8), (9, 10)) AS MyTable (a, b)

Ответ 3

Можно сделать в одной строке:

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

Изменить: Если вы имеете дело с очень большими числами, вам нужно будет преобразовать переменные значения в bigint, чтобы избежать переполнения целого числа.

Ответ 4

Я так не думаю. Я хотел это на днях. Ближайший я получил:

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

Ответ 5

Почему бы не попробовать функцию IIF (требуется SQL Server 2012 и более поздние версии)

IIF(a>b, a, b)

Это.

(Подсказка: будьте осторожны, если оба значения будут null, поскольку результат a>b будет ложным, если любой из них равен нулю. Поэтому в этом случае b будет результатом)

Ответ 6

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

Ответ 7

Другие ответы хороши, но если вам нужно беспокоиться о значениях 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

Sub Queries могут обращаться к столбцам из запроса Outer, поэтому вы можете использовать этот подход для использования агрегатов, таких как 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

Ответ 9

SQL Server 2012 представил IIF:

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

Рекомендуется использовать NULL при использовании IIF, потому что NULL по обе стороны вашего boolean_expression приведет к возврату IIF false_value (в отличие от NULL).

Ответ 10

Я бы пошел с решением, предоставленным 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

ИЗМЕНИТЬ Изменено после комментария Mark. Как он правильно указал в 3-значной логике x > NULL или x < NULL всегда должен возвращать NULL. Другими словами, неизвестный результат.

Ответ 11

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

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;

Ответ 12

Упс, я просто разместил обман этого вопроса...

Ответ: встроенная функция не существует, например 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

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

Ответ 13

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

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

Ответ 14

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

Ответ 15

Вот версия 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))

Ответ 16

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

Ответ 17

Вы можете сделать что-то вроде этого:

select case when o.NegotiatedPrice > o.SuggestedPrice 
then o.NegotiatedPrice
else o.SuggestedPrice
end

Ответ 18

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

Ответ 19

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

Ответ 20

Для ответа выше, касающегося больших чисел, вы можете сделать умножение до сложения/вычитания. Это немного громоздко, но не требует никакого броска. (Я не могу говорить за скорость, но я предполагаю, что это все еще довольно быстро)

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

Изменения в

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

по крайней мере альтернатива, если вы хотите избежать кастинга.

Ответ 21

В своей простейшей форме...

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

Ответ 22

Для SQL Server 2012:

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

Ответ 23

Вот ответ @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

Ответ 24

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

Ответ 25

В Presto вы можете использовать

SELECT array_max(ARRAY[o.NegotiatedPrice, o.SuggestedPrice])