Suite à ma dernière question ( Variables de table dans Oracle PL/SQL? ) ...
Une fois que vous avez des valeurs dans un tableau/table, comment les récupérer à nouveau? Utiliser de préférence une instruction select ou quelque chose de similaire?
Voici ce que j'ai jusqu'à présent:
declare
type array is table of number index by binary_integer;
pidms array;
begin
for i in (
select distinct sgbstdn_pidm
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH'
)
loop
pidms(pidms.count+1) := i.sgbstdn_pidm;
end loop;
select *
from pidms; --Oracle DOESN'T LIKE THIS BIT!!!
end;
Je sais que je peux les produire en utilisant dbms_output.putline (), mais j'espère obtenir un jeu de résultats comme je le ferais en le sélectionnant dans n'importe quelle autre table.
Merci d'avance, Matt
Vous pourriez avoir besoin d'une TABLE TEMPORAIRE GLOBALE.
Dans Oracle, ils sont créés une fois, puis lorsqu'ils sont invoqués, les données sont privées pour votre session.
Essayez quelque chose comme ça ...
CREATE GLOBAL TEMPORARY TABLE temp_number
( number_column NUMBER( 10, 0 )
)
ON COMMIT DELETE ROWS;
BEGIN
INSERT INTO temp_number
( number_column )
( select distinct sgbstdn_pidm
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH'
);
FOR pidms_rec IN ( SELECT number_column FROM temp_number )
LOOP
-- Do something here
NULL;
END LOOP;
END;
/
Dans Oracle, les moteurs PL/SQL et SQL maintiennent une certaine séparation. Lorsque vous exécutez une instruction SQL dans PL/SQL, elle est transmise au moteur SQL, qui n'a aucune connaissance des structures spécifiques à PL/SQL comme les tables INDEX BY.
Ainsi, au lieu de déclarer le type dans le bloc PL/SQL, vous devez créer un type de collection équivalent dans le schéma de base de données:
CREATE OR REPLACE TYPE array is table of number;
/
Ensuite, vous pouvez l'utiliser comme dans ces deux exemples dans PL/SQL:
SQL> l
1 declare
2 p array := array();
3 begin
4 for i in (select level from dual connect by level < 10) loop
5 p.extend;
6 p(p.count) := i.level;
7 end loop;
8 for x in (select column_value from table(cast(p as array))) loop
9 dbms_output.put_line(x.column_value);
10 end loop;
11* end;
SQL> /
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
SQL> l
1 declare
2 p array := array();
3 begin
4 select level bulk collect into p from dual connect by level < 10;
5 for x in (select column_value from table(cast(p as array))) loop
6 dbms_output.put_line(x.column_value);
7 end loop;
8* end;
SQL> /
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
Exemple supplémentaire basé sur des commentaires
Sur la base de votre commentaire sur ma réponse et sur la question elle-même, je pense que c'est ainsi que je l'appliquerais. Utilisez un package pour que les enregistrements puissent être récupérés une fois dans la table réelle et stockés dans un package privé global; et avoir une fonction qui renvoie un curseur ref ouvert.
CREATE OR REPLACE PACKAGE p_cache AS
FUNCTION get_p_cursor RETURN sys_refcursor;
END p_cache;
/
CREATE OR REPLACE PACKAGE BODY p_cache AS
cache_array array;
FUNCTION get_p_cursor RETURN sys_refcursor IS
pCursor sys_refcursor;
BEGIN
OPEN pCursor FOR SELECT * from TABLE(CAST(cache_array AS array));
RETURN pCursor;
END get_p_cursor;
-- Package initialization runs once in each session that references the package
BEGIN
SELECT level BULK COLLECT INTO cache_array FROM dual CONNECT BY LEVEL < 10;
END p_cache;
/
Le type de tableau SQL n'est pas nécessaire. Pas si le type d'élément est primitif. (Varchar, numéro, date, ...)
Échantillon très basique:
declare
type TPidmList is table of sgbstdn.sgbstdn_pidm%type;
pidms TPidmList;
begin
select distinct sgbstdn_pidm
bulk collect into pidms
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH';
-- do something with pidms
open :someCursor for
select value(t) pidm
from table(pidms) t;
end;
Lorsque vous souhaitez le réutiliser, il peut être intéressant de savoir à quoi cela ressemblerait. Si vous émettez plusieurs commandes, celles-ci pourraient être regroupées dans un package. L'astuce de la variable de package privé ci-dessus a ses inconvénients. Lorsque vous ajoutez des variables à un package, vous lui donnez l'état et maintenant il n'agit plus comme un groupe de fonctions sans état mais comme une sorte étrange d'instance d'objet singleton.
par exemple. Lorsque vous recompilez le corps, il lèvera des exceptions dans les sessions qui l'ont déjà utilisé auparavant. (parce que les valeurs des variables ont été invalidées)
Cependant, vous pouvez déclarer le type dans un package (ou globalement en sql) et l'utiliser comme paramètre dans les méthodes qui devraient l'utiliser.
create package Abc as
type TPidmList is table of sgbstdn.sgbstdn_pidm%type;
function CreateList(majorCode in Varchar,
program in Varchar) return TPidmList;
function Test1(list in TPidmList) return PLS_Integer;
-- "in" to make it immutable so that PL/SQL can pass a pointer instead of a copy
procedure Test2(list in TPidmList);
end;
create package body Abc as
function CreateList(majorCode in Varchar,
program in Varchar) return TPidmList is
result TPidmList;
begin
select distinct sgbstdn_pidm
bulk collect into result
from sgbstdn
where sgbstdn_majr_code_1 = majorCode
and sgbstdn_program_1 = program;
return result;
end;
function Test1(list in TPidmList) return PLS_Integer is
result PLS_Integer := 0;
begin
if list is null or list.Count = 0 then
return result;
end if;
for i in list.First .. list.Last loop
if ... then
result := result + list(i);
end if;
end loop;
end;
procedure Test2(list in TPidmList) as
begin
...
end;
return result;
end;
Comment l'appeler:
declare
pidms constant Abc.TPidmList := Abc.CreateList('HS04', 'HSCOMPH');
xyz PLS_Integer;
begin
Abc.Test2(pidms);
xyz := Abc.Test1(pidms);
...
open :someCursor for
select value(t) as Pidm,
xyz as SomeValue
from table(pidms) t;
end;