遍历循环以查找重复的名称

时间:2015-01-21 12:20:33

标签: sql oracle plsql

我从查询得到以下结果,我是一个plsql块,我将记录和send_email循环到客户。

enter image description here

匿名阻止

FOR i IN (SELECT product_no, product_holder,product_catalogue FROM
product_master)
LOOP
mail_send('PRODMASTER',i.product_holder, i.product_no,i.product_catalogue);
END LOOP;

我想知道如果product_holder在查询结果中重复,而不是发送多封电子邮件,希望发送一封包含相关详细信息的电子邮件,那么最佳方法是什么。例如。在上面的情况下,SMITH重复两次,因此使用上述方法SMITH将收到两封电子邮件,而我希望通过SMITHproduct_no

product_catalogue发送一封电子邮件

我该怎么做?

2 个答案:

答案 0 :(得分:5)

不要在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_sendproduct_holder程序发送的内容是包含product_noproduct_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

使用GROUP BY在SQL中执行此操作可以为您提供从PL / SQL到SQL的单个调用中的所有内容,这比第一次调用获得product_holder的独特集合要高效得多。 ,循环遍历,然后按product_holder进行一次调用,以获得每个持有者的产品。

更新:

在上面的代码中为order by函数添加了collect,以表明您可以控制数据在集合中的填充顺序。

答案 1 :(得分:1)

您可以使用两个循环并为每个产品持有者发送邮件,如下所示;

FOR i IN (SELECT distinct product_holder FROM
product_master)
LOOP
 v_products := null;
v_catalogs := null;
for product in (SELECT pm.product_no, pm.product_catalogue FROM
                    product_master pm where pm.product_holder = i.product_holder)
loop
    if v_products is null then
        v_products := product.product_no;
    else
        v_products := v_products ||', ' ||product.product_no;
    end if;
    if v_catalogs is null then
        v_catalogs := product.product_catalogue;
    else
        v_catalogs := v_catalogs ||', ' ||product.product_catalogue;
    end if;
end loop;
mail_send('PRODMASTER',i.product_holder, v_products,v_catalogs);
END LOOP;