我想写这样的查询:
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。
有人知道我该怎么做吗?
Answers:
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
所有的赞誉和投票都应该交给Sven对一个相关问题的答案:“多列的SQL MAX?”
我说这是“ 最佳答案 ”,因为:
可以一行完成:
-- 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
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个值。
即使其中之一为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
但是,如果需要对多个值求和?
然后,我建议交叉应用“值”的汇总。
这还具有可以同时计算其他事物的好处。
例:
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
在您的两边的a 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
编辑 在Mark发表评论后修改。正如他在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's 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
您可以执行以下操作:
select case when o.NegotiatedPrice > o.SuggestedPrice
then o.NegotiatedPrice
else o.SuggestedPrice
end
-- 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
or 更简单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
聚合中包含多个列来模拟支持。