Question

Comment créer une procédure stockée Oracle acceptant un nombre variable de valeurs de paramètres utilisées pour alimenter une clause IN?

C'est ce que j'essaie de réaliser. Je ne sais pas comment déclarer dans PLSQL pour avoir passé une liste variable de clés primaires des lignes que je veux mettre à jour.

FUNCTION EXECUTE_UPDATE
  ( <parameter_list>
   value IN int)
  RETURN  int IS
BEGIN 
    [...other statements...]
    update table1 set col1 = col1 - value where id in (<parameter_list>) 

    RETURN SQL%ROWCOUNT ;
END;

De plus, j'aimerais appeler cette procédure depuis C #. Elle doit donc être compatible avec les fonctionnalités .NET.

Merci, Robert

Était-ce utile?

La solution

Utiliser CSV est probablement la méthode la plus simple, en supposant que vous puissiez être certain à 100% que vos éléments ne contiendront pas de chaînes.

Une autre solution, et probablement plus robuste, consiste à créer un type personnalisé sous la forme d'une table de chaînes. En supposant que vos chaînes ne dépassent jamais 100 caractères, vous pourriez alors avoir:

CREATE TYPE string_table AS TABLE OF varchar2(100);

Vous pouvez ensuite passer une variable de ce type dans votre procédure stockée et la référencer directement. Dans votre cas, quelque chose comme ceci:

FUNCTION EXECUTE_UPDATE(
    identifierList string_table,
    value int)
RETURN int
IS
BEGIN

    [...other stuff...]

    update table1 set col1 = col1 - value 
    where id in (select column_value from table(identifierList));

    RETURN SQL%ROWCOUNT;

END

La fonction table () transforme votre type personnalisé en une table avec une seule colonne "COLUMN_VALUE", que vous pouvez ensuite traiter comme toute autre table (ainsi, les jointures ou, dans ce cas, sous-sélection).

La beauté de cela est qu'Oracle créera un constructeur pour vous. Ainsi, lorsque vous appelez votre procédure stockée, vous pouvez simplement écrire:

execute_update(string_table('foo','bar','baz'), 32);

Je suppose que vous pouvez gérer la construction de cette commande par programmation à partir de C #.

Par ailleurs, dans mon entreprise, un certain nombre de ces types personnalisés sont définis en tant que normes pour les listes de chaînes, doubles, entêtes, etc. Nous utilisons également Oracle JPublisher pour pouvoir mappez directement à partir de ces types dans les objets Java correspondants. J'ai jeté un coup d'œil autour de moi, mais je ne pouvais voir aucun équivalent direct pour C #. Je pensais juste que je le mentionnerais au cas où des développeurs Java rencontreraient cette question.

Autres conseils

J'ai trouvé l'article suivant de Mark A. Williams qui, selon moi, serait un ajout utile à ce fil. L'article donne un bon exemple de passage de tableaux de C # à des procédures PL / SQL à l'aide de tableaux associatifs (TYPE myType IS TABLE OF mytable.row% TYPE INDEX BY PLS_INTEGER):

Grand article de Mark A. Williams

Je pense qu’il n’existe aucun moyen direct de créer des procédures avec un nombre variable de paramètres. Cependant, il existe des solutions au moins partielles au problème, décrites ici .

  1. S'il existe des types d'appels types, une surcharge de procédure peut vous aider.
  2. S'il existe une limite supérieure au nombre de paramètres (et que leur type est également connu à l'avance), les valeurs par défaut des paramètres peuvent être utiles.
  3. La meilleure option est peut-être l'utilisation de variables de curseur, qui sont des pointeurs vers des curseurs de base de données.

Malheureusement, je n'ai aucune expérience des environnements .NET.

Pourquoi ne pas simplement utiliser une longue liste de paramètres et charger les valeurs dans un constructeur de table? Voici le SQL / PSM pour cette astuce

UPDATE Foobar
   SET x = 42
 WHERE Foobar.keycol
      IN (SELECT X.parm
            FROM (VALUES (in_p01), (in_p02), .., (in_p99)) X(parm)
           WHERE X.parm IS NOT NULL);

Pourquoi doit-il s'agir d'une procédure stockée? Vous pouvez créer une instruction préparée par programme.

Je ne l'ai pas encore fait pour Oracle, mais avec SQL Server, vous pouvez utiliser une fonction pour convertir une chaîne CSV en une table, qui peut ensuite être utilisée dans une clause IN. Il devrait être facile de ré-écrire ceci pour Oracle (je pense!)

CREATE Function dbo.CsvToInt ( @Array varchar(1000)) 
returns @IntTable table 
    (IntValue nvarchar(100))
AS
begin

    declare @separator char(1)
    set @separator = ','

    declare @separator_position int 
    declare @array_value varchar(1000) 

    set @array = @array + ','

    while patindex('%,%' , @array) <> 0 
    begin

      select @separator_position =  patindex('%,%' , @array)
      select @array_value = left(@array, @separator_position - 1)

        Insert @IntTable
        Values (Cast(@array_value as nvarchar))

      select @array = stuff(@array, 1, @separator_position, '')
    end

    return
end

Ensuite, vous pouvez passer une chaîne CSV (par exemple, '0001,0002,0003') et faire quelque chose comme

UPDATE table1 SET 
       col1 = col1 - value 
WHERE id in (SELECT * FROM csvToInt(@myParam)) 

Un article sur le site Web AskTom explique comment créer une fonction permettant d'analyser la chaîne CSV et de l'utiliser dans votre instruction de manière similaire à l'exemple de SQL Server donné.

Voir Asktom

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top