Hay un máximo de la función en SQL Server que toma dos valores tales como la Matemática.Max .NETA?

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

  •  02-07-2019
  •  | 
  •  

Pregunta

Quiero escribir una consulta como esta:

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

Pero esta no es la manera en la MAX funcionar funciona, ¿verdad?Es una función de agregado, de modo que se espera de un único parámetro y, a continuación, devuelve el máximo de todas las filas.

¿Alguien sabe cómo hacerlo a mi manera?

¿Fue útil?

Solución

Tendría que hacer un User-Defined Function si quería tener una sintaxis similar a su ejemplo, pero podría hacer lo que quieres hacer, en línea, de manera bastante sencilla con un CASE declaración, como los otros han dicho.

El UDF podría ser algo como esto:

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

...y lo podemos llamar así ...

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

Otros consejos

Si está utilizando SQL Server 2008 (o más), entonces esta es la mejor solución:

SELECT o.OrderId,
       (SELECT MAX(Price)
        FROM (VALUES (o.NegotiatedPrice),(o.SuggestedPrice)) AS AllPrices(Price))
FROM Order o

Todo el crédito y los votos deben ir a Sven respuesta a una pregunta relacionada, "SQL MAX de varias columnas?"
Me dicen que es el "mejor respuesta"porque:

  1. No es necesario complicar el código con la UNIÓN, de giro,de UNPIVOT s, UDF, y loco-larga CASO de instrucciones.
  2. No está plagado con el problema de manejo de valores nulos, se maneja muy bien.
  3. Es fácil cambiar el "MAX" con "MIN", "AVG", o de "SUMA".Se puede utilizar cualquier función de agregado para encontrar el agregado en diferentes columnas.
  4. Usted no está limitado a los nombres que he usado (es decir,"AllPrices" y "Precio").Usted puede escoger su propio nombre para hacerlo más fácil de leer y entender para el tipo de al lado.
  5. Usted puede encontrar varios agregados usando SQL Server 2008 derived_tables así:
    SELECT MAX(a), MAX(b) DE (VALORES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10) ) COMO MyTable(a, b)

Se puede hacer en una sola línea:

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

Editar: Si usted está tratando con números muy grandes tendrás que convertir el valor de las variables en bigint con el fin de evitar un desbordamiento de enteros.

Yo no lo creo.Yo quería el otro día.El más cercano que me dieron fue:

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

¿Por qué no probar IIF función (requiere SQL Server 2012 y posteriores)

IIF(a>b, a, b)

Eso es todo.

(Sugerencia:tenga cuidado acerca de cualquiera de ellos sería null, dado que el resultado de a>b será falsa cuando es nulo.Así b será el resultado en este caso)

DECLARE @MAX INT
@MAX = (SELECT MAX(VALUE) 
               FROM (SELECT 1 AS VALUE UNION 
                     SELECT 2 AS VALUE) AS T1)

Las otras respuestas son buenas, pero si usted tiene que preocuparse de tener valores NULL, usted puede querer esta 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

Sub Consultas pueden acceder a las columnas de la consulta Externa así que usted puede utilizar este enfoque el uso de agregados tales como MAX a través de las columnas.(Probablemente más útil cuando hay un mayor número de columnas implicadas aunque)

;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 introdujo IIF:

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

Manejo de valores Nulos se recomienda cuando se utiliza IIF, porque un NULL en cualquiera de los lados de su boolean_expression hará IIF para devolver el false_value (en contraposición a la NULL).

Me gustaría ir con la solución proporcionada por kcrumley Sólo tiene que modificar ligeramente para manejar valores Nulos

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

EDITAR Modificado después del comentario de Marca.Como bien señaló en 3 valores de logic x > NULL o x < NULL siempre debe devolver NULL.En otras palabras resultado desconocido.

Su tan simple como esto:

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;

Uy, me acaba de publicar un la víctima de esta pregunta...

La respuesta es que no hay ninguna construido en función de como Oracle Mayor, pero usted puede lograr un resultado similar por 2 columnas con una UDF, tenga en cuenta, el uso de sql_variant es muy importante aquí.

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

Publicado esta respuesta:

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

He aquí un ejemplo que deberían manejar los nulos y funcionará con versiones anteriores de MSSQL.Esto se basa en la función inline en un uno de los populares ejemplos:

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

Probablemente yo no lo haría de esta manera, ya que es menos eficiente que el ya mencionado CASO de las construcciones - a menos que, tal vez, tenían índices de cobertura para ambas consultas.De cualquier manera, es una técnica útil para problemas similares:

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

Aquí está una IIF versión con el manejo de NULOS (basado en el de Xin de la respuesta):

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

La lógica es la siguiente, si alguno de los valores es NULO, devolver el uno que no es NULA (si ambos están NULL, se devuelve NULL).En caso contrario, devuelve el mayor de uno.

Mismo puede ser hecho por MIN.

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

Usted puede hacer algo como esto:

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

Para la respuesta anterior respecto de los grandes números, usted podría hacer la multiplicación antes que la suma/resta.Es un poco más voluminoso, pero no requiere de fundición.(No puedo hablar por la velocidad, pero supongo que todavía es bastante rápido)

SELECCIONE 0.5 * ((@val1 + @val2) + ABS(@val1 - @val2))

Los cambios

SELECT @val1*0.5+@val2*0.5 + ABS(@val1*0.5 - @val2*0.5)

al menos una alternativa si desea evitar la proyección.

En su forma más simple...

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

Para SQL Server 2012:

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

En SQL Server 2012 o posterior, puede utilizar una combinación de IIF y ISNULL (o COALESCE) para obtener el máximo de 2 valores.
Incluso cuando el 1 de ellos es NULO.

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

O si usted desea devolver 0 cuando ambos son NULL

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

Ejemplo de fragmento:

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

Resultado:

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

Aquí está @Scott Langham la respuesta con el simple manejo de NULOS:

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]

En Presto usted podría utilizar

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;

La expansión en Xin respuesta y suponiendo que el valor de comparación es de tipo INT, este enfoque también funciona:

SELECT IIF(ISNULL(@A, -2147483648) > ISNULL(@B, -2147483648), @A, @B)

Esta es una prueba completa con los valores de ejemplo:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top