it-swarm.com.de

Gibt es in SQL Server eine Max-Funktion, die zwei Werte wie Math.Max ​​in .NET annimmt?

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?

405
skb

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
140
Kevin Crumley

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:

  1. Es ist nicht notwendig, Ihren Code mit den UNION-, PIVOT-, UNPIVOT-, UDF- und verrückten CASE-Statements zu komplizieren.
  2. Es ist nicht mit dem Problem der Handhabung von Nullen behaftet, es geht gut mit ihnen um.
  3. Das "MAX" kann einfach mit "MIN", "AVG" oder "SUM" ausgetauscht werden. Sie können jede Aggregatfunktion verwenden, um das Aggregat über viele verschiedene Spalten zu finden.
  4. Sie sind nicht auf die Namen beschränkt, die ich verwendet habe (d. H. "AllPreise" und "Preis"). Sie können Ihre eigenen Namen auswählen, um das Lesen und Verstehen für den nächsten Mann zu erleichtern.
  5. Sie können mehrere Aggregate mithilfe von abgeleiteten_Tabellen von SQL Server 2008 finden:
    SELECT MAX (a), MAX (b) FROM (WERTE (1, 2), (3, 4), (5, 6), (7, 8), (9, 10)) AS MyTable (a, b)
400
MikeTeeVee

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. 

203
splattne

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
120
Scott Langham

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.)

54
Xin Wang
DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)
30
jbeanky

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
11
D Nesmith

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
8
Martin Smith

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). 

6
SetFreeByTruth

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.

5
kristof

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;
4
Uri Abramson

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

kristof

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
3
Sam Saffron

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
3
scradam

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
2
Mark Brackett
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
2
Tom Arleth

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))
2
jahu

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
1
jsmink

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
1
Wayne

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. 

1
deepee1

Für SQL Server 2012:

SELECT 
    o.OrderId, 
    IIF( o.NegotiatedPrice >= o.SuggestedPrice,
         o.NegotiatedPrice, 
         ISNULL(o.SuggestedPrice, o.NegiatedPrice) 
    )
FROM 
    Order o
1
Steve Ford
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
1
andrewc

In Presto könntest du verwenden

SELECT array_max(ARRAY[o.NegotiatedPrice, o.SuggestedPrice])
0
maxymoo
 -- 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;
0
ashraf mohammed

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
0
Chris Porter
select OrderId, (
    select max([Price]) from (
        select NegotiatedPrice [Price]
        union all
        select SuggestedPrice
    ) p
) from [Order]
0
error

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
0
mohghaderi

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
0
LukStorms