【问题标题】:Indefinite number of arguments for SQL User Defined Functions?SQL用户定义函数的参数数量不定?
【发布时间】:2011-12-28 13:06:51
【问题描述】:

在 Oracle 和 MySQL 中,我如何创建一个接受不定数量参数的函数,以便可以像 GREATEST(value1,value2,...) 一样调用它?

按照某个标准比较两个值非常容易,但是将“更大”的值传递给另一个比较是我在 SQL 中似乎没有得到的工作。

谢谢!

编辑(在迈克下面的评论之后): 我正在寻找一种比较多列的解决方案。具体来说,我的问题是如何将 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 的解决方案

【问题讨论】:

  • 这和-select * from, order by x desc/asc 一样吗 最大值必须是第一个/最后一个?即使在 XSLt 中,我也只是对事物进行排序以获得最大值?
  • 大概你的意思是 SQL Server - SQL(没有进一步限定)是指一种语言,由各种不同的产品在不同程度上实现,并且每个产品都有自己独特的扩展。
  • 这是一种可以更好地扩展 case 语句的方法。 stackoverflow.com/questions/7995945/…
  • 您要比较多少列?如果数量不多,可以使用SELECT Max(Col4, Max(Col3, MAX(Col1, Col2))) FROM myTable
  • 很遗憾,IN 不能与比较运算符一起使用,而 ALL 和 ANY 不能与表达式/列列表一起使用。 MAX/MIN 函数也不能跨列工作。但这是个好主意。像下面这样嵌套一个 GREATER(或 LESSER)函数怎么样? DELIMITER // CREATE FUNCTION greater(i1 int, i2 int) RETURNS int BEGIN DECLARE o int; CASE WHEN i1 &gt;= i2 THEN SET o = i1; ELSE SET o = i2; END CASE; RETURN o; END //

标签: mysql sql oracle user-defined-functions


【解决方案1】:

在 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 

【讨论】:

    【解决方案2】:

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

    在将整数 ID 列表放入以逗号分隔的列表并提供给函数以获得最大 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
    

    【讨论】:

      猜你喜欢
      • 2016-11-25
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-30
      • 2020-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多