次のようなクエリを書きたいと思います。
SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
しかし、これは機能がどのようにMAX
機能するかではありませんよね?これは集計関数であるため、単一のパラメーターを想定し、すべての行の MAX を返します。
私のやり方を知っている人はいますか?
次のようなクエリを書きたいと思います。
SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
しかし、これは機能がどのようにMAX
機能するかではありませんよね?これは集計関数であるため、単一のパラメーターを想定し、すべての行の MAX を返します。
私のやり方を知っている人はいますか?
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行で実行できます:
-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2))
編集: 非常に大きな数を扱っている場合は、整数のオーバーフローを避けるために値変数を bigint に変換する必要があります。
あなたの例に似た構文が必要な場合は、を作成する必要がありますが、他の人が言ったように、ステートメントを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
私はそうは思わない。これが先日欲しかった。私が得た最も近いものは次のとおりです。
SELECT
o.OrderId,
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice
ELSE o.SuggestedPrice
END
FROM Order o
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE)
FROM (SELECT 1 AS VALUE UNION
SELECT 2 AS VALUE) AS T1)
他の答えは良いですが、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
サブクエリは外部クエリから列にアクセスできるため、このアプローチを使用して列間などの集計を使用でき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
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を返す必要があります。言い換えれば、未知の結果です。
おっと、私はちょうどこの質問のだましを投稿しました...
答えは、 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
おそらく、両方のクエリのインデックスをカバーしていない限り、前述の 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
大きな数に関する上記の答えについては、加算/減算の前に乗算を行うことができます。少しかさばりますが、キャストは必要ありません。(速度については言えませんが、それでもかなり速いと思います)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2))
への変更
SELECT @val1*0.5+@val2*0.5 + ABS(@val1*0.5 - @val2*0.5)
キャストを避けたい場合は、少なくとも代替手段です。
null を処理する必要があり、古いバージョンの MSSQL で動作するケースの例を次に示します。これは、一般的な例の 1 つであるインライン関数に基づいています。
case
when a >= b then a
else isnull(b,a)
end
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 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
最も単純な形で...
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 2012 の場合:
SELECT
o.OrderId,
IIF( o.NegotiatedPrice >= o.SuggestedPrice,
o.NegotiatedPrice,
ISNULL(o.SuggestedPrice, o.NegiatedPrice)
)
FROM
Order o