2011-11-14 4 views
6

W Oracle i MySQL, w jaki sposób mogę utworzyć funkcję, która ma nieokreśloną liczbę parametrów, aby można było nazywać się GREATEST (wartość1, wartość2, ...)?Nieokreślona liczba argumentów dla funkcji zdefiniowanych przez użytkownika SQL?

Porównanie dwóch wartości według pewnego standardu jest dość łatwe, ale przekazanie wartości "większej" do kolejnego porównania jest tym, co wydaje mi się, że nie pracuję w SQL.

Dzięki!

Edytuj (po komentarzu Mike'a poniżej): Szukam rozwiązania do porównywania wielu kolumn. Konkretnie, moje pytanie brzmi: jak wdrożyć GREATEST() jako UDF. Poniższy kod porównuje trzy kolumny.

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; 

Wygląda na to, że nie jest tak dobrze. O wiele bardziej przydatna będzie ogólna funkcja, która wielokrotnie stosuje tę samą metodę porównania do listy wartości.

przez SQL mam na myśli żadnego produktu bazodanowego SQL ale wolę rozwiązanie, które działa w Oracle lub MySQL

+0

Jest to tak samo jak - wybierz * od, zamówienie według x desc/asc Maksymalna wartość musi być pierwsza/ostatnia? Nawet w XSLt, po prostu sortuję rzeczy, aby uzyskać maksymalną wartość? – Mike

+0

Prawdopodobnie masz na myśli SQL Server - SQL (bez dalszych kwalifikacji) odnosi się do języka, wdrażanego w różnym stopniu przez różne różne produkty, oraz każdego z ich własnymi unikalnymi rozszerzeniami. –

+2

Oto jeden ze sposobów, który skaluje o wiele lepiej instrukcję 'case'. http://stackoverflow.com/questions/7995945/how-to-i-modify-this-t-sql-query-to-return-maximum-value-for-different-colum/7996068#7996068 –

Odpowiedz

2

w Oracle (przypadkach, które obsługują UNPIVOT)

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

Oracle zapytanie jest niesprawdzone, ponieważ Nie mam instancji pod ręką Więcej informacji na temat unpivot to located here i działa to samo, co SQL Server unpivot.

MySQL jestem pewny jak to zrobić w MySQL, ale może zbadać, jak mam okazję

Poniżej SQL odpowiedzi serwera (chyba że ktoś bije mnie do niego ;-).):

Wykonanie tego w UDF nie jest ładne, ponieważ wszystkie parametry wejściowe będą WYMAGANE w każdym przypadku. Jeśli mógłbyś uniknąć implementacji jako procedury przechowywanej, możesz określić wartości domyślne dla parametrów wejściowych i wywołać je z dynamiczną liczbą kolumn. Tak czy inaczej, będziesz musiał zdecydować o maksymalnej liczbie parametrów wejściowych. Oto przykład w UDF na 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 

będzie to wymagać nowego UDF dla każdego wariantu liczby parametrów wejściowych lub tworząc jeden, który mógłby przyjąć większą liczbę, ale potem w wywołaniu UDF ciebie musiałby podać jakąś wartość dla każdego nieużywanego parametru (null) lub określić wartość domyślną.

Alternatywy:

Daje to maksymalną wartość z trzech kolumn z całej tabeli i łatwiej byłoby mieć szereg dynamicznych kolumn:

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

Zakładając, że masz jakieś ROWID lub inną kolumnę, której chcesz użyć na wyjściu, aby uzyskać najwyższą wartość z określonych kolumn dla każdego wiersza. Możesz wykonać coś takiego:

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

Inna opcja SQL Server (nie wiem, jak dobrze będzie to przetłumaczyć na MySQL/Oracle).

miałem to zrobić z listą identyfikatorów całkowitych przed który kładę na listę oddzielonych przecinkami i wprowadza się do funkcji, aby uzyskać największą:

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