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

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

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

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

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

Это реализовано в большинстве других баз данных как функция GREATEST; SQLite эмулирует поддержку, позволяя использовать несколько столбцов в агрегате MAX.

OMG Ponies 21.10.2010 19:54

Возможный дубликат stackoverflow.com/questions/71022/sql-max-of-multiple-column‌ s

Michael Freidgeim 13.07.2011 15:56

При поиске решения для max (a, b) ниже помните о том, хотите ли вы, чтобы синтаксис или вычисление для «a» и / или «b» повторялись. Т.е. если «b» получено из сложных вычислений с использованием большого количества синтаксиса, тогда вы можете предпочесть решение, в котором «b» появляется только один раз. Например. решение «IIF (a> b, a, b)» означает повторение «b», что может быть синтаксически некрасивым, однако следующее решение означает, что «b» (и «a») появляются только один раз: SELECT MAX (VALUE) FROM (ВЫБЕРИТЕ a КАК ЗНАЧЕНИЕ СОЕДИНЕНИЕ ВЫБРАТЬ b КАК ЗНАЧЕНИЕ) КАК T1

Andrew Jens 24.03.2017 05:48
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
526
3
501 541
30
Перейти к ответу Данный вопрос помечен как решенный

Ответы 30

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

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

Это мой любимый метод. Вы не рискуете переполнением, и это менее загадочно, чем решение splattne (что, кстати, круто), и у меня нет проблем с созданием UDF. чехол очень удобен во многих ситуациях.

Lance Fisher 24.12.2011 02:29

ВЫБЕРИТЕ o.OrderId, СЛУЧАЙ, КОГДА o.NegotiatedPrice> o.SuggestedPrice ИЛИ o.SuggestedPrice IS NULL, ТО o.NegotiatedPrice ELSE o.SuggestedPrice END FROM Order o

mohghaderi 20.04.2017 18:08

Когда вместо «o.NegotiatedPrice» используется термин «(dateiff (day, convert (datetime, adr_known_since, 120), getdate ()) - 5) * 0.3», вам необходимо повторить этот код. Любые будущие изменения срока необходимо делать дважды. Функция типа min (x, y, ...) была бы намного лучше

Daniel 26.05.2020 15:25

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

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

иначе isnull (oSuggestedPrice, o, NegotiatedPrice)

CashCow 24.06.2020 12:16

Я бы, вероятно, не стал делать это таким образом, поскольку он менее эффективен, чем уже упомянутые конструкции 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. Если вы просто измените последнюю строку: «return @ value2» на «return isnull (@ val2, @ val1)», тогда, если одно из значений равно null, функция вернет ненулевое значение, в противном случае она будет работать как обычный

kristof 24.09.2008 14:32

А как насчет других типов данных, например мне нужно написать HigherIntegerArgument и HigherDateTimeArgument и HigherVarcharArgument и ...?

onedaywhen 10.06.2009 17:27

это будет невероятно медленно, как и все скалярные UDF. Вместо этого используйте встроенные UDF

A-K 21.10.2010 20:55

Можно ли сделать что-то подобное, чтобы получить наименьшее из двух значений?

Thomas 23.12.2010 11:24

@xan Я понятия не имею, что пришло мне в голову, когда я на самом деле задал этот вопрос. Очевидно, не слишком много. В любом случае спасибо за ответ.

Thomas 16.12.2011 17:21

@Thomas Не беспокойтесь - я тоже время от времени задавал такие же вопросы. Иногда мозг просто слишком много думает ...

xan 19.12.2011 19:57

@Thomas Обязательное изображение мема (ни в коем случае не в оскорбление!) flickr.com/photos/16201371@N00/2375571206

xan 19.12.2011 19:58

Это решение имеет преимущество работы с любым типом данных, для которого определен >.

Maxy-B 24.01.2012 19:32

Обратите внимание, что отредактированное решение обрабатывает значения NULL, такие как Max (), по запросу (Max возвращает наибольшее значение, отличное от NULL), но не работает так же, как простые сравнения> (которые возвращают NULL, если любой из аргументов имеет значение NULL). При использовании в другом контексте это может привести к потенциально противоречивым результатам, например к утверждению, что -999999999 больше нуля. Я переименовал функцию, чтобы она больше не подразумевала, что она действует как «больше чем».

Kevin Crumley 07.02.2012 23:57

Этот ответ не работает, если разработчик, пишущий запрос, не имеет разрешения на создание пользовательских функций и не может убедить администраторов баз данных сделать это. Я предпочитаю ответы Д. Несмита и Марка Брэкетта. Хотя изменение ISNULL на COALESCE сделало бы ответ Д. Несмита более переносимым.

dougp 23.10.2020 22:43

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

Требуется только ISNULL после ELSE. Первоначальное сравнение ">" вернет false и перейдет к ELSE, если какое-либо из значений уже равно нулю.

Phil B 30.08.2019 13:22

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

РЕДАКТИРОВАТЬ Изменено после комментария отметка. Как он правильно указал в трехзначной логике, x> NULL или x <NULL всегда должны возвращать NULL. Другими словами неизвестный результат.

Нули важны. И важно обращаться с ними последовательно. Единственный правильный ответ на Is NULL> x - NULL.

Mark Brackett 10.10.2008 04:27

Вы правы, я изменю свой ответ, чтобы отразить это, спасибо, что указали на это

kristof 13.10.2008 11:48

Если мы передадим int и NULL, тогда, я думаю, более распространено возвращение ненулевого значения, поэтому функция действует как комбинация Max (x, y) и ISNULL (x, y). Следовательно, я лично изменил бы последнюю строку на: return ISNULL (@ val1, @ val2) - что, по общему признанию, вероятно, то, с чего вам нужно было начать :)

redcalx 26.10.2009 17:17

@ the-locster, см. комментарий Марка

kristof 17.01.2010 04:32

@ the-lobster, я согласен, что это более распространено, но см. комментарий Марка, значения NULL важны, и, как он указывает, «Единственный правильный ответ на Is NULL> x is NULL»

kristof 17.01.2010 04:34

это будет невероятно медленно, как и все скалярные UDF. Вместо этого используйте встроенные UDF

A-K 21.10.2010 20:55

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

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

Примечание: реализация функции GREATEST будет соответствовать поведению оракула для 2 параметров, если какой-либо параметр равен null, он вернет null

Sam Saffron 13.10.2008 15:41

Будьте осторожны при использовании sql_variant. Ваша функция выдаст неожиданный результат в следующей ситуации: SELECT dbo.greatest (CAST (0.5 AS FLOAT), 100)

Neil 02.06.2011 19:43

@ Нил прав (я усвоил это на собственном горьком опыте), как бы вы улучшили эту функцию, чтобы предотвратить подобные проблемы?

Luca 20.09.2016 13:58

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

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

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

+1 Я считаю, что вы предоставили самый правильный способ. «SELECT ((@ val1 + @ val2) + ABS (@ val1- @ val2)) / 2 as MAX_OF_TWO» Также помните, «SELECT ((@ val1 + @ val2) - ABS (@ val1- @ val2)) / 2 как MIN_OF_TWO ".

tom 05.06.2009 00:00

Этот способ выдаст ошибку переполнения, если сумма больше, чем может быть сохранена в int: declare @ val1 int declare @ val2 int set @ val1 = 1500000000 set @ val2 = 1500000000 SELECT 0.5 * ((@ val1 + @ val2) + ABS (@ val1 - @ val2)) - => ошибка переполнения

AakashM 10.06.2009 17:02

Я такого раньше не видел. Гений.

redcalx 26.10.2009 16:18

Это крайне «грязный» «трюк». При программировании ваш код должен явно выражать цель, однако в вашем случае он выглядит как код, взятый из конкурса обфускации.

greenoldman 11.01.2011 12:50

Он может быть «грязным», но это может быть единственный вариант для баз данных с простыми диалектами SQL.

splattne 11.01.2011 15:16

Я не согласен с марсиасом. Код не обязательно сам по себе должен явно выражать цель, если комментарии позволяют решить ее. Если вы выполняете какие-либо сложные математические уравнения в коде (или где-то еще), иногда бывает сложно сделать его информативным. Пока он разбит на более простые и понятные части, это правильное программирование.

Rob 18.03.2011 07:32

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

KingErroneous 18.05.2011 19:43

@King, это не с плавающей точкой, скажем, если вы замените * 0.5 на div 2, это снова целочисленная математика. Это также будет очень хорошо работать в другом коде, потому что вы избегаете перехода «если-то» и, следовательно, неверного предсказания ветви (очевидно, за счет более длинного критического пути).

Johan 30.06.2011 15:45

Это будет работать для целых чисел и т. д., Но не для других типов данных, таких как datetime (что было моим конкретным вариантом использования - создайте столбец в наборе результатов, который в каждой строке имеет максимум (т. Е. Самый последний) из двух столбцов даты ).

Maxy-B 24.01.2012 19:24

Старый поток, который я знаю, но это работает для дат (используется формула выше): dateadd(dd, ((datediff(dd, 0, [Date1]) + datediff(dd, 0, [Date2])) + abs(datediff(dd, 0, [Date1]) - datediff(dd, 0, [Date2]))) / 2, 0)

Adrian Torrie 24.07.2013 05:03

Поскольку это было не сразу очевидно, это работает, потому что выражение ABS вычисляет величину разницы между минимальным и максимальным значением. Если добавить это обратно к сумме минимального и максимального значений, сумма будет в два раза больше максимального значения (которое всегда делится на 2). Деление на 2 возвращает максимальное значение. Я считаю, что вы можете изменить это, чтобы достичь функциональности MIN, вычитая выражение ABS вместо добавления.

Michael Petito 21.05.2015 20:18

Потеря точности при использовании типов с плавающей запятой означает, что вы можете не получить фактическое максимальное значение, а только число, которое действительно близко.

Trisped 09.07.2015 23:14

@futureSPQR: CAST (0.5 * ((CAST (@ val1 as float) + CAST (@ val2 AS float)) + ABS (cast (@ val1 as float) - CAST (@ val2 AS float))) AS datetime)

Stefan Steiger 27.07.2016 14:45

Проголосовали против, потому что он использует смекалку там, где доступно чистое решение. Он также выдает число, которое не может быть гарантировано равным какому-либо столбцу из-за арифметических ошибок округления. Следует использовать оператор CASE (или эквивалентную функцию IIF, если она доступна). Гринольдман сказал это правильно.

xxyzzy 11.12.2017 12:49

Если любое значение равно нулю, вы получите ноль. Наверное, не то, что нужно.

Ross Presser 14.02.2019 00:33

Кто-то отработал доказательство

Mr.Z 18.03.2019 22:36

Определенно элегантное решение, которое избегает сравнения ... Спасибо!

bastio84 10.06.2020 13:00

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

Я даю этому решению +1, потому что оно соответствует DRY (не повторяйтесь) без необходимости писать UDF. Также замечательно, если оба значения, которые вам нужно проверить, являются результатами другого sql, например, в моем случае я хочу найти большее из двух операторов select count (*).

MikeKulls 23.03.2012 03:41

Я ненавижу то, что мне приходится прибегать к этому решению, но это, безусловно, лучший способ сделать это в SQL Server, пока они не добавят встроенную поддержку GREATEST или встроенного MAX. Спасибо за публикацию - +1 вам!

SqlRyan 04.05.2012 23:48

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

Хороший! Он очень хорошо масштабируется.

greenoldman 11.01.2011 12:52

+1, чтобы показать Любовь к тем, кто еще в 2005 году. Не знаю, как я пропустил этот ответ. Под обложками, я полагаю, он работает так же хорошо, как то, что я опубликовал 2 года спустя. Оглядываясь назад, я должен был это понять и обновить ваш ответ, включив в него более новый синтаксис 2008 года. Извините, я хотел бы поделиться с вами своими баллами сейчас.

MikeTeeVee 07.12.2015 03:48

@MikeTeeVee - Спасибо! Да под одеялом план будет такой же. Но синтаксис VALUES лучше.

Martin Smith 07.12.2015 23:05

хороший ответ, потому что он работает во всех версиях, включая новый Azure DW / synapse, который не поддерживает VALUES ()

jkmelbs 05.08.2020 04:27

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

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

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

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

+1 единственный ответ, не требующий доступа для создания процедуры / функций!

Alex 16.04.2012 15:25

Именно такой ответ я искал. Использование функций происходит медленно, и это также будет работать с датами, что мне и нужно.

Johann Strydom 29.06.2012 15:08

+1 Отлично работает, особенно для сравнения более двух столбцов!

JanW 30.08.2012 14:44

Это менее производительно, чем решение CASE WHEN, которое требует только вычисления скаляра.

tekumara 31.03.2013 05:21

@tukushan Я не заметил никаких проблем с производительностью, используя это в своих запросах (и я использовал его несколько раз для заполнения своего хранилища данных, а также в нашей онлайн-отчетности). С помощью оператора CASE вам нужно будет добавить проверки NULL для его правильной работы, и мы все знаем, что проверка на NULL будет снижать производительность, если вы пытаетесь доить каждую наносекунду. Честно говоря, я не нашел времени, чтобы запустить кучу тестов для сравнения, но я не запускал эти тесты, потому что они настолько молниеносные, что мне не нужно искать более быстрый вариант.

MikeTeeVee 31.03.2013 08:58

Возможно, вы правы - я тоже не особо разбирался в этом. Но я заметил, что план запроса, созданный для вышеуказанного, дороже, чем решение CASE.

tekumara 01.04.2013 00:42

Хотя более простой синтаксис может никогда не стоить снижения производительности при определении MAX из 2 значений, это может быть другое дело с большим количеством значений. Даже при получении MAX, равного 4 значениям, предложения CASE становятся длинными, неуклюжими и подверженными ошибкам, если генерируются вручную, в то время как предложение VALUES остается простым и понятным.

Typhlosaurus 16.06.2014 19:05

Не может использоваться, если результат требуется в агрегатной функции: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.

Thorarin 03.03.2015 09:57

@Thorarin Просто используйте @variable для сохранения результата, а затем агрегируйте его

asakura89 09.03.2015 09:23

Случайно и по незнанию нажал «против» и больше не может его изменить. Извиняюсь! Ответ действительно помог мне!

Hugo Delsing 31.08.2015 14:15

И синтаксис, совместимый с SQL Server 2005, в моем нелюбимом ответе, опубликованном двумя годами ранее! stackoverflow.com/a/3989370/73226

Martin Smith 06.12.2015 18:37

Предупреждение - я использовал это в операторе UPDATE в форме SET x = (SELECT MAX (CopyCount) FROM (VALUES (x - 1), (0)) AS Copies (CopyCount)), и он работал ужасно и иногда приводил к дал мне ошибки, когда база данных больше не могла обновлять строку.

Evan M 28.06.2016 23:05

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

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;

См. Комментарий @Neil к предыдущему ответу SELECT dbo.InlineMax (CAST (0.5 AS FLOAT), 100) неверен.

Luca 20.09.2016 14:06

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, потому что NULL на любой стороне вашего boolean_expression заставит IIF вернуть false_value (в отличие от NULL).

Ваше решение не будет правильно обрабатывать NULL, когда другое значение отрицательно, это вернет null

t-clausen.dk 07.12.2015 16:09

Для SQL Server 2012:

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

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

IIF(a>b, a, b)

Вот и все.

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

Если одно из значений NULL, результатом всегда будет второе.

jahu 06.09.2017 14:44

IIF () - это синтаксический сахар для оператора CASE. Если одно из значений условного оператора CASE равно NULL, результатом будет второе значение (ELSE).

xxyzzy 11.12.2017 13:04

@xxyzzy, потому что утверждение NULL > 1234 неверно

Xin 11.12.2017 14:02

поэтому IIF(a>b, a, COALESCE(b,a)) дает значение, когда существует только один

mpag 28.06.2019 01:42

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

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

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

Для объяснения, пожалуйста, обратитесь к этой статье: red-gate.com/simple-talk/sql/sql-training/…

Tom Arleth 14.09.2018 14:42

Пожалуйста, не включайте необходимую информацию в свой код просто по ссылке. Представьте, что однажды эта ссылка истечет, и тогда ваш ответ будет бесполезен. Поэтому, пожалуйста, добавьте основную информацию прямо в свой ответ. Но вы все равно можете предоставить эту ссылку в качестве ресурса, чтобы другие могли найти дополнительную информацию.

L. Guthardt 14.09.2018 14:44

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

Хотя использование VALUES интересно, я не уверен, что это проще, чем CASE или IFF. Мне было бы интересно увидеть, как производительность этого решения складывается по сравнению с другими вариантами, хотя

Chris Schaller 01.02.2020 01:43

Расширяя ответ 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 или более поздней версии вы можете использовать комбинацию 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

Но если нужно максимум несколько столбцов?
Затем я предлагаю КРЕСТНОЕ ПРИМЕНЕНИЕ к агрегированию ЗНАЧЕНИЙ.

Пример:

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)

Другие вопросы по теме