2011-11-14 14 views
6

In Oracle e MySQL, come posso creare una funzione che richiede un numero indefinito di parametri in modo che possa essere chiamata GREATEST (valore1, valore2, ...)?Numero indefinito di argomenti per le funzioni definite dall'utente SQL?

Confrontare due valori con un determinato standard è piuttosto semplice ma passare il valore "maggiore" a un altro confronto è quello che non sembra funzionare in SQL.

Grazie!

Edit (dopo il commento di Mike sottostante): Sto cercando una soluzione per il confronto di più colonne. In termini concreti, la mia domanda è come implementare GREATEST() come UDF. Il seguente codice confronta tre colonne.

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; 

Apparentemente, questo non è scalabile così bene. Sarà molto più utile avere una funzione generale che applica sempre lo stesso metodo di confronto a un elenco di valori.

da SQL intendo qualsiasi prodotto di database SQL, ma io preferisco una soluzione che funziona in Oracle o MySQL

+0

È questo lo stesso - selezionare * da, ordina per x desc/asc Il valore massimo deve il primo/ultimo? Anche in XSLt, ho solo risolto le cose per ottenere il valore massimo? – Mike

+0

Presumibilmente si intende SQL Server - SQL (senza ulteriore qualifica) si riferisce a un linguaggio, implementato a vari livelli da vari prodotti diversi, e ciascuno con le proprie estensioni univoche. –

+2

Ecco un modo per ridimensionare molto meglio l'istruzione 'case'. http://stackoverflow.com/questions/7995945/how-to-i-modify-this-t-sql-query-to-return-the-maximum-value-for-different-colum/7996068#7996068 –

risposta

2

In (casi che supportano UNPIVOT) Oracle

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

query di Oracle è testato a causa Non ho un'istanza a portata di mano Ulteriori dettagli su unpivot sono located here e fa la stessa cosa di unpivot di SQL Server.

MySQL io sono sicuro di come fare questo in MySQL, ma può indagare come ho occasione

Le seguenti sono le risposte di SQL Server (a meno che qualcuno mi batte ad esso ;-).):

L'operazione in una UDF non è carina perché tutti i parametri di input sono OBBLIGATORI in ogni caso. Se si riesce a cavarsela con l'implementazione come stored procedure, è possibile specificare i valori predefiniti per i parametri di input e chiamarla con un numero dinamico di colonne. In entrambi i casi, dovrai decidere un numero massimo di parametri di input. Ecco un esempio in UDF 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 

Ciò richiederebbe una nuova UDF per ciascuna variante del numero di parametri di input o la creazione di uno che potrebbe richiedere un numero maggiore ma poi nella chiamata al FSU voi dovrebbe specificare un valore per ogni parametro non utilizzato (null) o specificare il valore predefinito.

Alternative:

questo ti dà il valore massimo delle tre colonne da tutto il tavolo e sarebbe più facile avere un numero dinamica di colonne:

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

Supponendo di avere un po 'di rowid o un'altra colonna che si desidera nell'output in modo da ottenere il massimo dalle colonne specificate per ogni riga, si potrebbe fare qualcosa di simile:

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

Un'altra opzione di SQL Server (non so quanto bene si tradurrà in MySQL/Oracle).

ho avuto a che fare questo con un elenco di ID interi prima che ho messo in un elenco delimitato da virgole e alimentato ad una funzione per ottenere il massimo:

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 
Problemi correlati