575

次のようなクエリを書きたいと思います。

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

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

私のやり方を知っている人はいますか?

4

31 に答える 31

537

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

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

すべての功績と投票は、関連する質問「SQL MAX of multiple columns?」に対する Sven の回答に委ねるべきです。
私はそれが「最良の答え」だと言います:

  1. UNION、PIVOT、UNPIVOT、UDF、および非常に長い CASE ステートメントでコードを複雑にする必要はありません。
  2. null の処理の問題に悩まされることはなく、問題なく処理されます。
  3. 「MAX」を「MIN」、「AVG」、または「SUM」に置き換えるのは簡単です。集計関数を使用して、多くの異なる列の集計を見つけることができます。
  4. 私が使用した名前 (つまり、「AllPrices」と「Price」) に限定されません。次の人が読みやすく理解しやすいように、独自の名前を選択できます。
  5. SELECT MAX(a), MAX(b) FROM (VALUES (1, 2), (3, 4), (5, 6), (7, 8 ) ,
    (9, 10) ) AS MyTable(a, b)
于 2012-02-25T23:55:17.270 に答える
244

1行で実行できます:

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

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

于 2008-11-16T11:45:57.837 に答える
182

あなたの例に似た構文が必要な場合は、を作成する必要がありますが、他の人が言ったように、ステートメントを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
于 2008-09-23T23:03:06.697 に答える
134

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

SELECT
  o.OrderId,
  CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice 
     ELSE o.SuggestedPrice
  END
FROM Order o
于 2008-09-23T22:56:15.887 に答える
35
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)
于 2010-05-20T14:09:08.580 に答える
12

他の答えは良いですが、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
于 2008-09-24T02:41:39.137 に答える
11

サブクエリは外部クエリから列にアクセスできるため、このアプローチを使用して列間などの集計を使用でき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
于 2010-10-21T15:53:22.500 に答える
6

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

編集マーク からのコメントの後に変更されました。彼が3値論理で正しく指摘したように、x>NULLまたはx<NULLは常にNULLを返す必要があります。言い換えれば、未知の結果です。

于 2008-09-24T09:56:59.183 に答える
4

おっと、私はちょうどこの質問のだましを投稿しました...

答えは、 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
于 2008-10-13T08:18:46.010 に答える
4

おそらく、両方のクエリのインデックスをカバーしていない限り、前述の 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
于 2008-09-23T23:02:26.057 に答える
3

大きな数に関する上記の答えについては、加算/減算の前に乗算を行うことができます。少しかさばりますが、キャストは必要ありません。(速度については言えませんが、それでもかなり速いと思います)

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

への変更

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

キャストを避けたい場合は、少なくとも代替手段です。

于 2010-10-21T15:46:23.173 に答える
3

null を処理する必要があり、古いバージョンの MSSQL で動作するケースの例を次に示します。これは、一般的な例の 1 つであるインライン関数に基づいています。

case
  when a >= b then a
  else isnull(b,a)
end
于 2016-10-24T14:35:00.267 に答える
2
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
于 2010-06-07T16:37:43.873 に答える
2

次のようなことができます。

select case when o.NegotiatedPrice > o.SuggestedPrice 
then o.NegotiatedPrice
else o.SuggestedPrice
end
于 2008-09-23T22:57:18.003 に答える
2
SELECT o.OrderID
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN
 o.NegotiatedPrice
ELSE
 o.SuggestedPrice
END AS Price
于 2008-09-23T22:57:20.297 に答える
1

最も単純な形で...

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
于 2011-02-18T19:42:05.477 に答える
1

SQL Server 2012 の場合:

SELECT 
    o.OrderId, 
    IIF( o.NegotiatedPrice >= o.SuggestedPrice,
         o.NegotiatedPrice, 
         ISNULL(o.SuggestedPrice, o.NegiatedPrice) 
    )
FROM 
    Order o
于 2015-12-07T12:45:35.557 に答える