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

StackOverflow https://stackoverflow.com/questions/124417

  •  02-07-2019
  •  | 
  •  

Frage

Ich möchte eine Abfrage wie folgt schreiben:

SELECT o.OrderId, MAX(o.NegotiatedPrice, o.SuggestedPrice)
FROM Order o

Das ist aber nicht, wie die MAX Funktion funktioniert, nicht wahr? Es ist eine Aggregatfunktion, so dass es einen einzigen Parameter erwartet und gibt dann den MAX alle Zeilen.

Wer weiß, wie es meine Art und Weise zu tun?

War es hilfreich?

Lösung

Sie müssen eine User-Defined Function machen, wenn Sie ähnliche Syntax zu Ihrem Beispiel haben wollen, aber könnten Sie tun, was Sie tun wollen, inline, ziemlich leicht mit einer CASE Aussage, wie die andere gesagt haben.

Die UDF so etwas wie dies sein könnte:

create function dbo.InlineMax(@val1 int, @val2 int)
returns int
as
begin
  if @val1 > @val2
    return @val1
  return isnull(@val2,@val1)
end

... und Sie würden es wie so nennen ...

SELECT o.OrderId, dbo.InlineMax(o.NegotiatedPrice, o.SuggestedPrice) 
FROM Order o

Andere Tipps

Wenn Sie mit SQL Server 2008 (oder höher), dann 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 Kredit- und Stimmen sollte Svens Antwort auf eine ähnliche Frage: „SQL MAX mehrerer Spalten?“ Go to
ich sagen, es ist die " beste Antwort ", weil:

  1. Es erfordert nicht Ihren Code mit UNION, PIVOT die komplizieren, UNPIVOT ist, UDF und verrückt langen CASE statments.
  2. Es ist nicht mit dem Problem der Handhabung nulls geplagt, es behandelt sie gut.
  3. Es ist einfach, den "MAX" mit "MIN", "AVG" oder "SUM" zu tauschen. Sie können eine beliebige Aggregatfunktion verwenden, um die Summe über viele verschiedene Spalten zu finden.
  4. Sie sind auf die Namen nicht beschränkt I verwendet (das heißt „AllPrices“ und „Preis“). Sie können Ihren eigenen Namen wählen, um es einfacher für den nächsten Mann zu lesen und zu verstehen.
  5. Sie können mehrere Aggregate mit SQL Server 2008 derived_tables finden wie so :
    SELECT MAX (a), MAX (b) (die Werte (1, 2), (3, 4), (5, 6), (7, 8), (9, 10)) als MyTable ( a, b)

Kann in einer Zeile durchgeführt werden:

-- the following expression calculates ==> max(@val1, @val2)
SELECT 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2)) 

Edit:. Wenn Sie mit sehr großen Zahlen zu tun haben Sie die Wertvariablen in Bigint um umwandeln müssen, um einen Integer-Überlauf zu vermeiden

Das glaube ich nicht so. Ich wollte dies den anderen Tag. Der nächstgelegene ich bekam, war:

SELECT
  o.OrderId,
  CASE WHEN o.NegotiatedPrice > o.SuggestedPrice THEN o.NegotiatedPrice 
     ELSE o.SuggestedPrice
  END
FROM Order o

Warum nicht versuchen, IIF Funktion (erfordert SQL Server 2012 und höher)

IIF(a>b, a, b)

Das ist es.

(Hinweis: vorsichtig sein, entweder null würde, da das Ergebnis von a>b falsch sein wird, wenn entweder null So b das Ergebnis in diesem Fall sein wird).

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 mit NULL-Werte zu befürchten haben, können Sie diese Variante wollen:

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 die Spalten aus der äußeren Abfrage zugreifen, so dass Sie dieser Ansatz Aggregate wie MAX über mehrere Spalten zu verwenden. (Wahrscheinlich nützliche, wenn es eine größere Anzahl von Spalten obwohl beteiligt ist)

;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

NULLs Handhabung wird empfohlen, wenn IIF verwenden, weil ein NULL auf beiden Seiten der boolean_expression IIF bewirkt, dass der false_value zurückzukehren (im Gegensatz zu NULL).

würde ich mit der Lösung geht von kcrumley ändern Sie es einfach etwas NULLs zu behandeln

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

Bearbeiten Modifiziert nach Kommentar von Mark . Wie er richtig in 3 Werte-Logik x> NULL wies darauf hin, oder x

Seine so einfach wie folgt aus:

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;

Oops, ich habe gerade gebucht eine Betrogene dieser Frage ...

Die Antwort ist, gibt es keine integrierte Funktion ist wie Oracle größte , aber Sie können mit einem UDF, Notiz, die Verwendung von sql_variant ist sehr wichtig hier.

ein ähnliches Ergebnis für 2 Spalten erreichen
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

Veröffentlicht 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 ist ein Fallbeispiel, die NULL-Werte handhaben soll und wird mit älteren Versionen von MSSQL arbeiten. Dies basiert auf der Inline-Funktion in einem eines der beliebtesten Beispiele:

case
  when a >= b then a
  else isnull(b,a)
end

Ich würde wahrscheinlich es auf diese Weise nicht tun, da es weniger effizient ist als der bereits erwähnten Fall konstruiert - es sei denn, vielleicht haben Sie Indizes für beiden Abfragen abdecken. So oder so, es ist 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

Hier ist eine IIF-Version mit NULL Handhabung (basierend auf der Xin Antwort):

IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a > b, a, b))

Die Logik ist wie folgt, wenn eine der beiden Werte NULL ist, die eine zurückzugeben, die nicht NULL ist (wenn beide NULL sind, wird eine NULL zurückgegeben). Andernfalls die größeren zurück.

Das gleiche kann für MIN erfolgen.

IIF(a IS NULL OR b IS NULL, ISNULL(a,b), IIF(a < b, a, b))
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

Sie können 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
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

Für die Antwort oben in Bezug auf große Zahlen, könnten Sie die Multiplikation tun, bevor die Addition / Subtraktion. Es ist ein bisschen sperriger aber erfordert keine Besetzung. (Ich kann nicht für die Geschwindigkeit sprechen, aber ich nehme an, es ist immer noch ziemlich schnell)

  

0,5 SELECT * ((@ val1 + @ val2) +   ABS (@ val1 - @ val2))

Änderungen

  

SELECT @ val1 * 0,5 + @ val2 * 0,5 +   ABS (@ val1 * 0,5 - @ val2 * 0,5)

zumindest eine Alternative, wenn Sie Gießen vermeiden wollen.

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

Für SQL Server 2012:

SELECT 
    o.OrderId, 
    IIF( o.NegotiatedPrice >= o.SuggestedPrice,
         o.NegotiatedPrice, 
         ISNULL(o.SuggestedPrice, o.NegiatedPrice) 
    )
FROM 
    Order o

In SQL Server 2012 oder höher, können Sie eine Kombination aus IIF und ISNULL (oder COALESCE) die maximal 2 Werte zu erhalten.
Selbst wenn ein von ihnen ist NULL.

IIF(col1 >= col2, col1, ISNULL(col2, col1)) 

Oder wenn Sie es 0 zurück, wenn beide NULL sind

IIF(col1 >= col2, col1, COALESCE(col2, col1, 0)) 

Beispiel-Snippet:

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

Hier ist @ Scott Langham Antwort mit einfacher NULL Handhabung:

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

In Presto Sie Gebrauch verwenden könnten

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;

Die Erweiterung auf Xin Antwort und unter der Annahme des Vergleichswert Typ INT, dieser Ansatz funktioniert auch:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top