在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中运行的解决方案
答案 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