2011-11-14 22 views
6

En Oracle y MySQL, ¿cómo puedo crear una función que tome un número indefinido de parámetros para que se pueda llamar como GREATEST (value1, value2, ...)?Número indefinido de argumentos para las funciones definidas por el usuario de SQL?

Comparar dos valores para un cierto estándar es bastante fácil, pero pasar el "mayor" valor a otra comparación es lo que parece que no me funciona en SQL.

Gracias!

Editar (después del comentario de Mike a continuación): Estoy buscando una solución para comparar varias columnas. En términos concretos, mi pregunta es cómo implementar GREATEST() como un UDF. El siguiente código compara tres columnas.

SELECT CASE WHEN CASE WHEN col_1 < col_2 THEN col_2 
       ELSE col_1 END < col_3 THEN col_3 
     ELSE CASE WHEN col_1 < col_2 THEN col_2 
       ELSE col_1 END END AS greatest 
    FROM figures; 

Aparentemente, esto no escala tan bien. Será mucho más útil tener una función general que aplique el mismo método de comparación una y otra vez a una lista de valores.

Por SQL me refiero a cualquier producto de base de datos SQL, pero yo prefiero una solución que funciona en Oracle o MySQL

+0

Es esto lo mismo que - seleccionar * from, orden por x desc/asc El valor máximo debe ser el primero/el último? Incluso en XSLt, ¿solo ordeno las cosas para obtener el valor máximo? – Mike

+0

Probablemente se refiere a SQL Server - SQL (sin más calificación) se refiere a un lenguaje, implementado en diversos grados por varios productos diferentes, y cada uno con sus propias extensiones únicas también. –

+2

Aquí hay una manera de escalar mucho mejor la declaración 'case '. http://stackoverflow.com/questions/7995945/how-to-i-modify-this-t-sql-query-to-return-the-maximum-value-for-different-colum/7996068#7996068 –

Respuesta

2

En Oracle (instancias que apoyan UNPIVOT)

SELECT MyID, MAX(GreatestVal) 
FROM figures 
    UNPIVOT (
      GreatestVal 
      FOR MyID 
      IN (col_1, col_2, col_3,...) 
     ); 

consulta de Oracle no se ha probado porque No tengo una instancia útil Más detalles sobre unpivot son located here y hace lo mismo que el servidor SQL no se puede redirigir.

MySQL estoy seguro de cómo hacer esto en MySQL, pero puede investigar como tengo oportunidad

Las siguientes son respuestas de SQL Server (a menos que alguien me pega a él ;-).):

Hacerlo en una UDF no es bonito porque todos los parámetros de entrada SERÍAN REQUERIDOS en todos los casos. Si puede lograr implementarlo como un procedimiento almacenado, puede especificar valores predeterminados para los parámetros de entrada y llamarlo con un número dinámico de columnas. De cualquier manera, tendrá que decidir sobre una cantidad máxima de parámetros de entrada. Aquí es un ejemplo en el UDF en SQL Server:

SELECT dbo.GREATESTof3(col_1, col_2, col_3) 
FROM figures; 

CREATE FUNCTION GREATESTof3(@col_1 sql_variant = null, @col_2 sql_variant = null, @col_3 sql_variant = null) 
RETURNS sql_variant 
AS 
BEGIN 
    DECLARE @GreatestVal sql_variant 
    DECLARE @ColumnVals TABLE (Candidate sql_variant) 


    INSERT INTO @ColumnVals 
    SELECT @col_1 
    UNION ALL 
    SELECT @col_2 
    UNION ALL 
    SELECT @col_3 

    SELECT @GreatestVal = MAX(Candidate) 
    FROM @ColumnVals 

    RETURN @GreatestVal 
END 

Esto requeriría una nueva UDF para cada variante del número de parámetros de entrada o la creación de una que podría tener un número mayor, pero luego en la llamada a la UDF se Tendría que especificar algún valor para cada parámetro no utilizado (nulo) o especificar predeterminado.

Alternativas:

Esto le da el valor máximo de las tres columnas de la tabla entera y sería más fácil tener una serie dinámica de columnas:

SELECT MAX([Value]) AS Greatest 
FROM figures 
UNPIVOT 
(
    [Value] 
    FOR ColumnName IN ([Col_1], [Col_2], [Col_3]) 
) AS unpvt 

Asumiendo que tiene alguna rowid u otra columna que desee en la salida para que pueda obtener el máximo de las columnas especificadas para cada fila, puede hacer algo como esto:

SELECT RowID, MAX([Value]) AS Greatest 
FROM figures 
UNPIVOT 
(
    [Value] 
    FOR ColumnName IN ([Col_1], [Col_2], [Col_3]) 
) AS unpvt 
GROUP BY RowID 
0

Otra opción de SQL Server (no estoy seguro de qué tan bien se traducirá a MySQL/Oracle).

que he tenido que hacer esto con una lista de ID de número entero antes de que puse en una lista separada por comas y se alimenta a una función para obtener el mayor:

CREATE Function [dbo].[GreatestFromList] 
(@ListOfValues VARCHAR(8000)) 

RETURNS INT 

AS 

BEGIN 

DECLARE @ListOfValuesTable TABLE (ValueColumn INT) 

    DECLARE @spot1 SMALLINT, @str1 VARCHAR(8000) 

    WHILE @ListOfValues <> '' 
    BEGIN 
     SET @spot1 = CHARINDEX(',', @ListOfValues) 
     IF @spot1>0 
      BEGIN 
       SET @str1 = LEFT(@ListOfValues, @spot1-1) 
       SET @ListOfValues = RIGHT(@ListOfValues, LEN(@ListOfValues)[email protected]) 
      END 
     ELSE 
      BEGIN 
       SET @str1 = @ListOfValues 
       SET @ListOfValues = '' 
      END 
     INSERT INTO @ListOfValuesTable (ValueColumn) VALUES(convert(int, @str1)) 
    END 

DECLARE @GreatestValue INT 

SELECT @GreatestValue = SELECT MAX(ValueColumn) FROM @ListOfValuesTable 

RETURN @GreatestValue 

END 
Cuestiones relacionadas