Ich möchte eine Anfrage wie diese schreiben:
SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
Aber so funktioniert die Funktion MAX
nicht, oder? Da es sich um eine Aggregatfunktion handelt, erwartet sie einen einzelnen Parameter und gibt dann den MAX aller Zeilen zurück.
Weiß jemand, wie es auf meine Weise geht?
Sie müssten einen User-Defined Function
erstellen, wenn Sie eine Syntax haben möchten, die Ihrem Beispiel ähnlich ist, aber könnten Sie das tun, was Sie tun möchten, inline relativ leicht mit einer CASE
-Anweisung, wie die anderen gesagt haben.
Die UDF
könnte ungefähr so aussehen:
create function dbo.InlineMax(@val1 int, @val2 int)
returns int
as
begin
if @val1 > @val2
return @val1
return isnull(@val2,@val1)
end
... und du würdest es gerne so nennen ...
SELECT o.OrderId, dbo.InlineMax(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o
Wenn Sie SQL Server 2008 (oder höher) verwenden, ist dies die bessere Lösung:
SELECT o.OrderId,
(SELECT MAX(Price)
FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o
Alle Gutschriften und Stimmen sollten an Sven's Antwort auf eine verwandte Frage "SQL MAX mehrerer Spalten?" Gehen.
Ich sage, es ist das "beste Antwort", weil:
Kann in einer Zeile erfolgen:
-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2))
Edit: Bei sehr großen Zahlen müssen Sie die Wertvariablen in bigint konvertieren, um einen Ganzzahlüberlauf zu vermeiden.
Ich glaube nicht Ich wollte das neulich haben. Das nächste, was ich bekam, war:
SELECT
o.OrderId,
CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice
ELSE o.SuggestedPrice
END
FROM Order o
Warum probieren Sie nicht die FunktionIIF(erfordert SQL Server 2012 und höher)
IIF(a>b, a, b)
Das ist es.
(Hinweis: Seien Sie vorsichtig bei beidem wäre null
, da das Ergebnis von a>b
immer dann falsch ist, wenn einer der Werte null ist. In diesem Fall ist b
das Ergebnis.)
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE)
FROM (SELECT 1 AS VALUE UNION
SELECT 2 AS VALUE) AS T1)
Die anderen Antworten sind gut, aber wenn Sie sich Sorgen machen müssen, NULL-Werte zu haben, möchten Sie möglicherweise diese Variante:
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
Unterabfragen können über die äußere Abfrage auf die Spalten zugreifen, sodass Sie this approach verwenden können, um Aggregate wie MAX
zwischen den Spalten zu verwenden. (Wahrscheinlich sinnvoller, wenn mehr Spalten vorhanden sind)
;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
SQL Server 2012 eingeführt IIF
:
SELECT
o.OrderId,
IIF( ISNULL( o.NegotiatedPrice, 0 ) > ISNULL( o.SuggestedPrice, 0 ),
o.NegotiatedPrice,
o.SuggestedPrice
)
FROM
Order o
Die Verwendung von NULL-Werten wird bei Verwendung von IIF
empfohlen, da eine NULL
auf beiden Seiten Ihres boolean_expression
dazu führt, dass IIF
den false_value
zurückgibt (im Gegensatz zu NULL
).
Ich würde mit der von kcrumley .__ bereitgestellten Lösung gehen. Modifizieren Sie sie einfach, um NULLs zu verarbeiten
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 Nach Kommentar von Mark geändert. Wie er in der 3-wertigen Logik richtig angegeben hat, sollte x> NULL oder x <NULL immer NULL zurückgeben. Mit anderen Worten unbekanntes Ergebnis.
So einfach ist das:
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;
Ups, ich habe gerade ein Dupe dieser Frage gepostet ...
Die Antwort ist, es gibt keine eingebaute Funktion wie Oracle's Greatest , aber Sie können mit einer UDF ein ähnliches Ergebnis für 2 Spalten erzielen. Beachten Sie, dass die Verwendung von sql_variant hier sehr wichtig ist.
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
Gepostet diese Antwort:
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
Hier ein Fallbeispiel, das mit Nullwerten umgehen sollte und mit älteren MSSQL-Versionen funktioniert. Dies basiert auf der Inline-Funktion in einem der populären Beispiele:
case
when a >= b then a
else isnull(b,a)
end
Ich würde es wahrscheinlich nicht so machen, da es weniger effizient ist als die bereits erwähnten CASE-Konstrukte - es sei denn, Sie hatten vielleicht Indexe für beide Abfragen. So oder so ist es eine nützliche Technik für ähnliche Probleme:
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 o.OrderId,
--MAX(o.NegotiatedPrice, o.SuggestedPrice)
(SELECT MAX(v) FROM (VALUES (o.NegotiatedPrice), (o.SuggestedPrice)) AS value(v)) as ChoosenPrice
FROM Order o
Hier ist eine IIF-Version mit NULL-Behandlung (basierend auf Xins Antwort):
IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a > b, a, b))
Die Logik ist wie folgt: Wenn einer der Werte NULL ist, geben Sie den Wert zurück, der nicht NULL ist (wenn beide NULL sind, wird NULL zurückgegeben) Ansonsten den größeren zurückgeben.
Gleiches kann für MIN gemacht werden.
IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a < b, a, b))
In seiner einfachsten Form ...
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
Sie können so etwas tun:
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
Für die Antwort zu großen Zahlen können Sie die Multiplikation vor der Addition/Subtraktion durchführen. Es ist etwas voluminöser, erfordert aber keine Besetzung. (Ich kann nicht für Geschwindigkeit sprechen, aber ich gehe davon aus, dass es immer noch ziemlich schnell ist.)
SELECT 0.5 * ((@ val1 + @ val2) + ABS (@ val1 - @ val2))
Änderungen an
SELECT @ val1 * 0,5 + @ val2 * 0,5 + ABS (@ val1 * 0,5 - @ val2 * 0,5)
eine Alternative, wenn Sie Casting vermeiden möchten.
Für SQL Server 2012:
SELECT
o.OrderId,
IIF( o.NegotiatedPrice >= o.SuggestedPrice,
o.NegotiatedPrice,
ISNULL(o.SuggestedPrice, o.NegiatedPrice)
)
FROM
Order o
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
In Presto könntest du verwenden
SELECT array_max(ARRAY[o.NegotiatedPrice, o.SuggestedPrice])
-- 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;
Wenn Sie Xins Antwort erweitern und davon ausgehen, dass der Vergleichswerttyp INT ist, funktioniert dieser Ansatz ebenfalls:
SELECT IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)
Dies ist ein vollständiger Test mit Beispielwerten:
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
select OrderId, (
select max([Price]) from (
select NegotiatedPrice [Price]
union all
select SuggestedPrice
) p
) from [Order]
Hier ist die Antwort von @Scott Langham mit einfacher NULL-Behandlung:
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
In SQL Server 2012 oder höher können Sie eine Kombination aus IIF
und ISNULL
(oder COALESCE
) verwenden, um das Maximum von 2 Werten zu erhalten.
Selbst wenn einer von ihnen NULL ist.
IIF(col1 >= col2, col1, ISNULL(col2, col1))
Oder wenn Sie möchten, dass 0 zurückgegeben wird, wenn beide NULL sind
IIF(col1 >= col2, col1, COALESCE(col2, col1, 0))
Beispielausschnitt:
-- 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
Ergebnis:
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