【问题标题】:Getting rows that are having distinct id with bulk collect - Oracle使用批量收集获取具有不同 ID 的行 - Oracle
【发布时间】:2020-05-23 22:08:51
【问题描述】:

我想使用批量收集来获取具有不同成员 ID 的记录。 我的查询如下:

  ...
    type members_nt is table of table2%rowtype;
    members_bc      members_nt;
  ...
select t2.* bulk collect
        into members_bc
        from table1 t1
            ,table2 t2
       where t1.isn= t2.isn
         and t1.customer= customer
         and t1.insert_date between ... and ... );

t2 表有一个名为 member_id 的列,我想要进入 members_bc 的是具有不同 member_id 的行。

例如,如果我的 t2 表有这样的内容:

  name  |  surname  | account   | member_id 
  john       alby      abc         123   
  john       alby      def         123 
  mary       hale      lkj         234

我只想批量收集

name  |  surname  | account   | member_id
john       alby      abc          123
mary       hale      lkj          234

name  |  surname  | account   | member_id
john       alby      def          123
mary       hale      lkj          234

不管是哪一个。但 memberid 在 members_bc 中必须是唯一的。

我怎样才能做到这一点?谢谢。

【问题讨论】:

    标签: oracle plsql greatest-n-per-group


    【解决方案1】:

    使用ROW_NUMBER() 分析函数为每个member_id 分配一个数字,然后过滤以仅获取第一行。

    DECLARE
      TYPE members_nt IS TABLE OF table2%ROWTYPE;
      members_bc members_nt;
    BEGIN
      SELECT t2.name, t2.surname, t2.account, t2.member_id
      BULK COLLECT INTO members_bc
      FROM  (
        SELECT t2.*,
               ROW_NUMBER() OVER ( PARTITION BY member_id ORDER BY ROWNUM ) AS rn
        FROM   table2 t2
      ) t2
      WHERE  rn = 1;
    
      FOR i IN 1 .. members_bc.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE( members_bc(i).member_id || ' ' || members_bc(i).name );
      END LOOP;
    END;
    /
    

    输出:

    第123章 第234章

    db小提琴here

    【讨论】:

      【解决方案2】:

      您可以避免“选择 *”,只需为您的选择创建一个游标,然后创建游标的 %rowtype 来输入所需的列。 使用@MT0 答案作为基线模板。)

      declare
        cursor members_cur is 
               select t2.name, t2.surname, t2.account, t2.member_id
                 from ( select t2.name, t2.surname, t2.account, t2.member_id
                             , row_number() over ( partition by member_id order by rownum ) as rn
                         from table2 t2
                      ) t2
                where rn = 1;
      
        type members_tt is table of members_cur%rowtype;
        members_bc members_tt;
      begin
        open  members_cur; 
        fetch members_cur 
         bulk collect into members_bc;
        close members_cur; 
      
        for i in 1 .. members_bc.count 
        loop
          dbms_output.put_line(members_bc(i).member_id || ' ' ||members_bc(i).name);
        end loop;
      end;
      

      【讨论】:

        【解决方案3】:

        一个简单的选择是使用聚合,例如

        select name,  
               surname, 
               min(account) as account,        --> this
               member_id
        from ...
        group by name, surname, member_id      --> and this
        

        【讨论】:

        • 批量收集如何适应这个答案?在我的表中,我有很多列,所以我不想在 select 语句之后将它们一一写出来。我的问题是我找不到与批量收集到语句一起使用的解决方案。
        • 在生产系统中使用select * 很可能是错误的。出于快速/测试/开发目的 - 好的,我们都这样做。但是对于真正的东西,不用了,谢谢。顺便说一句,如果您开始打字,那么您已经结束了那些 很多列。不——我不是在开玩笑,也不是在取笑你——只是想告诉你什么是正确的做法。
        • SELECT * 在您使用 %ROWTYPE 数据类型时没有错,因为您希望所有列的顺序完全正确,并且如果表结构发生变化(而不是应该),那么您仍然会希望所有列的顺序完全正确,您只需要重新编译过程/包即可使 PL/SQL 正常工作。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多