Oracle
 sql >> база данни >  >> RDS >> Oracle

Преминете през цикъл, за да намерите повтарящи се имена

Не правете цикли в цикли в PL/SQL за това - използвайте SQL, за да ви предостави данните, готови за употреба.

Първо създаваме вашата таблица с някои тестови данни (предполагам типове данни - вие заменяте със свои собствени):

create table product_master (
   product_no        varchar2(10)
 , product_holder    varchar2(10)
 , product_catalogue varchar2(10)
)
/

insert into product_master values ('1', 'SMITH', 'TEMP')
/
insert into product_master values ('2', 'SMITH', 'TEMP')
/
insert into product_master values ('3', 'HARRY', 'ARCH')
/
insert into product_master values ('4', 'TOM'  , 'DEPL')
/
commit
/

Какво искаме да изпратим на mail_send процедура за всеки product_holder е колекция (масив), съдържаща product_no и product_catalogue . И така, първо тип, който съдържа тези два елемента:

create type t_prod_cat_no as object (
   product_no        varchar2(10)
 , product_catalogue varchar2(10)
)
/

И след това тип вложена таблица (тип колекция) от този тип:

create type t_prod_cat_no_table as
   table of t_prod_cat_no
/

Процедурата mail_send тогава трябва да приеме product_holder и типа колекция:

create or replace procedure mail_send (
   p_parameter        in varchar2
 , p_product_holder   in varchar2
 , p_product_cats_nos in t_prod_cat_no_table
)
is
begin
   dbms_output.put_line('-- BEGIN '||p_parameter||' --');
   dbms_output.put_line('Dear '||p_product_holder);
   dbms_output.put_line('Your products are:');
   for i in 1..p_product_cats_nos.count loop
      dbms_output.put_line(
         'Catalogue: '||p_product_cats_nos(i).product_catalogue||
         ' - No: '||p_product_cats_nos(i).product_no
      );
   end loop;
end mail_send;
/

(Просто използвам dbms_output, за да симулирам изграждане на поща.)

След това можете в SQL да направите group by product_holder и оставете SQL да генерира колекцията, съдържаща данните:

begin
   for holder in (
      select pm.product_holder
           , cast(
                collect(
                   t_prod_cat_no(pm.product_no,pm.product_catalogue)
                   order by pm.product_catalogue
                          , pm.product_no
                ) as t_prod_cat_no_table
             ) product_cats_nos 
        from product_master pm
       group by pm.product_holder
       order by pm.product_holder
   ) loop
      mail_send(
         'PRODMASTER'
       , holder.product_holder
       , holder.product_cats_nos
      );
   end loop;
end;
/

Резултатът от горния блок ще бъде:

-- BEGIN PRODMASTER --
Dear HARRY
Your products are:
Catalogue: ARCH - No: 3
-- BEGIN PRODMASTER --
Dear SMITH
Your products are:
Catalogue: TEMP - No: 1
Catalogue: TEMP - No: 2
-- BEGIN PRODMASTER --
Dear TOM
Your products are:
Catalogue: DEPL - No: 4

Правейки го в SQL с GROUP BY ви дава всичко в едно извикване от PL/SQL към SQL, което е много по-ефективно от първото едно извикване за получаване на различен набор от product_holder , преминете през това и след това по едно извикване на product_holder за да получите продуктите за всеки притежател.

АКТУАЛИЗАЦИЯ:

Добавен order by към collect функция в горния код, за да покаже, че имате контрол върху реда, в който данните се попълват в колекцията.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. няма привилегии за таблично пространство „ПОТРЕБИТЕЛИ“

  2. Как да мигрираме база данни на Oracle от AWS EC2 към AWS RDS

  3. Как да промените отрицателната стойност на положителна в Oracle?

  4. Oracle 11g - FOR цикъл, който вмъква само дни от седмицата в таблица?

  5. Oracle:Използване на псевдо стойност на колона в същия оператор Select