SQL用户定义函数的参数数量无限多?

时间:2011-11-14 10:29:03

标签: mysql sql oracle user-defined-functions

在Oracle和MySQL中,如何创建一个带有无限数量参数的函数,以便可以像GREATEST(value1,value2,...)一样调用它?

通过某个标准比较两个值非常简单,但将“更大”的值传递给另一个比较是我似乎无法在SQL中工作。

谢谢!

编辑(在Mike的评论之后): 我正在寻找比较多列的解决方案。具体而言,我的问题是如何将GREATEST()实现为UDF。以下代码比较了三列。

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;

显然,这不能很好地扩展。拥有一个将相同的比较方法一遍又一遍地应用于值列表的通用函数会更有用。

通过SQL我的意思是任何SQL数据库产品,但我更喜欢在Oracle或MySQL中运行的解决方案

2 个答案:

答案 0 :(得分:2)

在Oracle(支持unpivot的实例)

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

Oracle查询未经测试,因为我没有方便的实例 有关unpivot的更多详细信息是located here,它与SQL Server unpivot完全相同。

<强>的MySQL 我不确定如何在MySQL中执行此操作,但可以调查,因为我有机会(除非有人打败我。;-))

以下是SQL Server的答案:

在UDF中执行它并不漂亮,因为在每种情况下都需要所有输入参数。如果您可以将其作为存储过程实现,那么您可以为输入参数指定默认值,并使用动态列数调用它。无论哪种方式,您都必须决定最大数量的输入参数。以下是SQL Server上的UDF示例:

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

这将需要为输入参数数量的每个变体创建一个新的UDF,或者创建一个可能需要更多数量的UDF,但是在调用UDF时,您必须为每个未使用的参数指定一些值(null)或指定默认值。

<强>备选方案:

这为您提供了整个表中三列的最大值,并且更容易获得动态列数:

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

假设您在输出中有一些rowid或其他列,以便您可以从每行的指定列中获得最大值,您可以执行以下操作:

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

答案 1 :(得分:0)

另一个SQL Server选项(不确定它将如何转换为MySQL / Oracle)。

我必须使用整数ID列表执行此操作,然后将其放入以逗号分隔的列表并送入函数以获得最大值:

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)-@spot1)  
            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