web-dev-qa-db-ja.com

SQL Serverには、.NETのMath.Maxのように2つの値をとるMax関数がありますか。

私はこのようなクエリを書きたいです。

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

しかし、これはMAX関数がどのように機能するかではありませんね。これは集約関数なので、単一のパラメーターを想定してから、すべての行のMAXを返します。

誰かが私のやり方でそれを行う方法を知っていますか?

428
skb

あなたの例に似た構文を持ちたいなら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
142
Kevin Crumley

SQL Server 2008(またはそれ以上)を使用している場合は、これがより良い解決策です。

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

すべてのクレジットと投票は 関連する質問に対するSvenの回答 "SQL MAX of multiple columns?" に行くべきです
私はそれが " ベストアンサー "だと言っています。

  1. それはあなたのコードをUNION、PIVOT、UNPIVOT、UDF、そして狂気のCASE文で複雑にする必要はありません。
  2. それはnullを扱うという問題に悩まされていません、それはそれらをちょうどうまく扱います。
  3. "MAX"を "MIN"、 "AVG"、または "SUM"と交換するのは簡単です。集約関数を使用して、さまざまな列にわたる集約を見つけることができます。
  4. あなたは私が使った名前(すなわち "AllPrices"と "Price")に限定されない。次の人にとって読みやすく理解しやすいように、自分の名前を選ぶことができます。
  5. SQL Server 2008の derived_tables を使用して、次のように複数の集計を見つけることができます。
    MAX(a)、MAX(b)から選択(値(1、2)、(3、4)、(5、6)、(7、8)、(9、10))AS MyTable (a、b)
409
MikeTeeVee

一行で行うことができます。

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

編集: 非常に大きな数値を扱う場合は、整数のオーバーフローを回避するために値の変数をbigintに変換する必要があります。

208
splattne

私はそうは思わない。私は先日これが欲しかった。私が得た最も近いものは次のとおりです。

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

_ iif _ functionを試してみませんか(SQL Server 2012以降が必要)

IIF(a>b, a, b)

それでおしまい。

(ヒント:どちらかがnullの場合はa>bの結果はfalseになるため、nullになるように注意してください。したがって、この場合の結果はbになります)

59
Xin
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)
32
jbeanky

他の答えは良いですが、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
11
D Nesmith

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
8
Martin Smith

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ではなく)NULLfalse_valueを返すからです。

6
SetFreeByTruth

私は kcrumley によって提供された解決策を採用するでしょう。

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

_ edit _ Mark からのコメントの後に変更されました。彼が3値論理で正しく指摘したようにx> NULLまたはx <NULLは常にNULLを返すべきです。言い換えれば、未知の結果です。

5
kristof

それはこれと同じくらい簡単です:

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;
4
Uri Abramson

おっと、私はこの質問の を書いたところです ...

答えは、 OracleのGreatest のような組み込み関数はありませんが、UDFを使用して2列に対して同様の結果を得ることができます。ここでは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
3
Sam Saffron

これはnullを処理し、古いバージョンのMSSQLで動作するケースの例です。これは、よく使われる例の1つのインライン関数に基づいています。

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

すでに述べた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
Mark Brackett
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
2
Tom Arleth

これは、(Xinの答えに基づく)NULL処理を伴うIIFバージョンです。

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
jahu

その最も単純な形では...

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

あなたはこのようなことをすることができます:

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

大きい数に関して上の答えのために、あなたは足し算/引き算の前に掛け算をすることができました。少し大きくなりますが、キャストは必要ありません。 (私はスピードを話すことはできませんが、まだかなり早いと思います)

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

への変更

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

あなたがキャストを回避したい場合は、少なくとも代替手段。

1
deepee1

SQL Server 2012の場合:

SELECT 
    o.OrderId, 
    IIF( o.NegotiatedPrice >= o.SuggestedPrice,
         o.NegotiatedPrice, 
         ISNULL(o.SuggestedPrice, o.NegiatedPrice) 
    )
FROM 
    Order o
1
Steve Ford
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
andrewc

SQL Server 2012以降では、IIFISNULL(またはCOALESCE)を組み合わせて最大2つの値を取得できます。
1つが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
1
LukStorms

Prestoではuseを使うことができます

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

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
0
Chris Porter
select OrderId, (
    select max([Price]) from (
        select NegotiatedPrice [Price]
        union all
        select SuggestedPrice
    ) p
) from [Order]
0
error

これは@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
0
mohghaderi