私はこのようなクエリを書きたいです:
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を返します。
誰か私のやり方で知っていますか?
回答:
User-Defined Function
例に似た構文が必要な場合は、aを作成する必要がありますが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
SQL Server 2008(またはそれ以上)を使用している場合は、これがより良いソリューションです。
SELECT o.OrderId,
(SELECT MAX(Price)
FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o
すべてのクレジットと投票は、関連する質問「複数列のSQL MAX?」に対するSvenの回答に
行く必要があります。
「ベストアンサー」だと私は言います。
1行で実行できます。
-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2))
編集: 非常に大きな数値を扱う場合は、整数オーバーフローを回避するために値変数をbigintに変換する必要があります。
私はそうは思いません。先日これが欲しかった。私が得た最も近いものは:
SELECT
o.OrderId,
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice
ELSE o.SuggestedPrice
END
FROM Order o
IIF関数を試してみませんか(SQL Server 2012以降が必要です)
IIF(a>b, a, b)
それでおしまい。
(ヒント:どちらかがnullの場合は常にnull
結果a>b
がfalse になるため、どちらかがになることに注意してください。b
この場合は結果になります)
NULL
、結果は常に2番目の値になります。
NULL > 1234
文は偽である
IIF(a>b, a, COALESCE(b,a))
1つしか存在しない場合の値を示すため
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
SQL Server 2012以降ではIIF
、およびISNULL
(または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
しかし、複数の値を合計する必要がある場合はどうでしょうか。
次に、VALUESの集約にCROSS APPLYすることをお勧めします。
これには、同時に他のものも計算できるという利点もあります。
例:
SELECT t.*
, ca.[Total]
, ca.[Maximum]
, ca.[Minimum]
, ca.[Average]
FROM SomeTable t
CROSS APPLY (
SELECT
SUM(v.col) AS [Total],
MIN(v.col) AS [Minimum],
MAX(v.col) AS [Maximum],
AVG(v.col) AS [Average]
FROM (VALUES (t.Col1), (t.Col2), (t.Col3), (t.Col4)) v(col)
) ca
サブクエリは外部クエリから列にアクセスできるため、このアプローチを使用し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
VALUES
構文はより良いです。
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
)。
私は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を返す必要があります。つまり、不明な結果です。
これと同じくらい簡単です:
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;
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
おっと、私はこの質問の複製を投稿しました...
答えは、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 case when o.NegotiatedPrice > o.SuggestedPrice
then o.NegotiatedPrice
else o.SuggestedPrice
end
SQL Server 2012の場合:
SELECT
o.OrderId,
IIF( o.NegotiatedPrice >= o.SuggestedPrice,
o.NegotiatedPrice,
ISNULL(o.SuggestedPrice, o.NegiatedPrice)
)
FROM
Order o
-- 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
。このソリューションのパフォーマンスが他のオプションと比較してどのように優れているかを知りたいと思います
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
GREATEST
関数として実装されています。SQLiteは、MAX
集計で複数の列を許可することでサポートをエミュレートします。