【问题标题】:Grouping recursive cycle by common person按普通人分组递归循环
【发布时间】:2020-05-26 00:15:23
【问题描述】:

我对 PL/SQL 还很陌生,我正在为我得到的任务而苦苦挣扎。

我有法律实体和自然实体。每个法人实体可以有一些自然实体,这些自然实体可以绑定到一个或多个实体。

  • A 公司有 #1 和 #2 和 #3 的 disponent
  • B 公司有 #2 和 #4 的 disponent
  • C 公司有 4 号异议
  • 公司 D 有第 5 号异议
  • 公司 E 有第 6 号异议
  • F 公司有第 6 号异议

结果应该显示哪些公司是通过某些机构联系在一起的。实际上,关系更“深”和复杂。 在我的示例中,结果应该是这样的:

  • A 公司 - 第 1 组
  • 公司 B - 第 1 组
  • 公司 C - 第 1 组
  • 公司 D - 第 2 组
  • 公司 E - 第 3 组
  • F 公司 - 第 3 组

excel中的示例表:

我做了3张桌子:

  • SNAPSHOT_FO - 包含 FO_CLUID(自然实体的 ID)
  • SNAPSHOT_VAZBA - 包含 PO_cluid(法人 ID)和 FO_cluid。这是关系表。
  • ODLITE - 包含 FO_CLUID(自然实体的 ID)和 KOD(组 ID) - 开头为空。应该是决赛桌,然后我可以加入 PO_cluid 并获得结果。
CREATE GLOBAL TEMPORARY TABLE tbl_temp
(
   F_CL VARCHAR2(255) NULL,
   par NUMBER(5) NULL
)
ON COMMIT PRESERVE ROWS;

DECLARE
  party NUMBER := 1;
  r NUMBER := 1;

BEGIN
FOR CLUID IN (select FO_CLUID from snapshot_fo  WHERE ROWNUM =1)
LOOP
INSERT INTO tbl_temp (F_CL,par) VALUES (CLUID,party);

        WHILE  ( r> 0 )
        BEGIN

            MERGE INTO tbl_temp tg
            USING  ((SELECT distinct FO_CLUID from snapshot_vazba where PO_CLUID in (
                                                        SELECT distinct PO_CLUID 
                                                        from snapshot_vazba
                                                        where FO_CLUID in (select f_cl from tbl_temp where kod=party)
                                                    ))
            ) src
                on (tg.FO_cluid =src.FO_cluid)
            WHEN NOT MATCHED THEN
                INSERT (F_CL, par)
                VALUES (src.FO_CLUID, party)               
        SET r = SQL%ROWCOUNT
        END;
        INSERT INTO odlite (FO_CLUID, KOD) VALUES (tbl_temp.cluid,tbl_temp.party);
        delete from snapshot_fo where fo_cluid in (select fo_cluid from odlite);
        truncate table tbl_temp;
        party := party + 1;
        r := 1;
    END Loop;
end ;
/

然后我将odlite ON FO_cluid 加入我的PO_cluid 表。 但是代码目前不起作用......而且我不知道如何做到这一点。 如果有更简单的方法,请告诉我:)

PS:由于我们公司的限制,我不允许在声明部分制作临时表。

提前致谢!

ORACLE SQL 开发者版本 19.2.1.247

【问题讨论】:

  • 我也在考虑 Prior 和 Connect By,但我不确定是否可以用它来解决我的问题。

标签: sql oracle plsql cursor cycle


【解决方案1】:

我没有完全正确理解这个任务,但你可能需要它

select t1.po_cluid, t2.kod
  from snapshot_vazba t1
  join odlite t2 on t2.fo_cluid = t1.fo_cluid
 group by t1.po_cluid, t2.kod
 order by po_cluid, kod

然后你可以使用merge、insert into select、for循环,或者输入一个集合并根据需要进行处理

【讨论】:

  • 欢迎来到 SO Pavel。请查看How to Ask。将其作为您问题的模板会大大增加您获得满意答案的机会。特别是为所有表和示例数据发布 DDL - 全部作为文本没有图像 - 以及该数据的预期结果。就你的 PS 而言:很好,你的公司做得对;至少对于甲骨文而言。
  • Odlite 表一开始是空的。我只是展示了它应该是什么样子。
  • 您需要一个聚合属性。否则,使用链接映射很难显示你想要的数据
【解决方案2】:
select po_cluid, dense_rank() over (order by min(connect_by_root(rn))) kod
  from (select rownum rn, s.* from snapshot_vazba s) s
  connect by nocycle prior fo_cluid = fo_cluid or prior po_cluid = po_cluid
  group by po_cluid

dbfiddle demo

此查询返回所需的输出,但是如果表很大,恐怕它对您的数据库来说非常沉重。预计性能问题。它在公司 - disponent - 公司之间循环并找到最小的共同价值。 Dense_rank() 仅用于按顺序枚举值。

【讨论】:

  • 是的:/我也在考虑 Prior 和 Connect By,但是数据集太大而且为此复杂化。我有超过 7 万家公司,有些公司有 200 多家公司,有些公司与 200 多家公司有联系。但谢谢!这绝对是较小数据集的解决方案。
【解决方案3】:
declare
  v_cluid varchar2(30 char);
  v_party integer;
  change_num integer;

  function get_party return integer is
    grp integer;
  begin
    select
      nvl(max(kod),0)
    into
      grp
    from
      snapshot_vazba;

    return grp;
  end;

  function get_cluid return varchar2 is
    v_cluid varchar2(30 char);
  begin
    select
      nvl(max(fo_cluid), 'XNA')
    into
      v_cluid
    from
      (
        select
          fo_cluid,
          row_number() over (partition by 1 order by count_f desc) as rn
        from
          (
            select count(1) as count_f, fo_cluid from snapshot_vazba where kod is null group by fo_cluid
          )
      )
    where
      rn = 1;

    return v_cluid;
  end;
begin
  v_party := get_party + 1;
  v_cluid := get_cluid;

  while (v_cluid <> 'XNA' )
  loop
    update
      snapshot_vazba
    set
      kod = v_party
    where
      po_cluid in (select po_cluid from snapshot_vazba where fo_cluid = v_cluid) and kod is null;

    update
      snapshot_vazba
    set
      kod = v_party
    where
      kod is null and
      fo_cluid in (select fo_cluid from snapshot_vazba where kod = v_party);

    change_num := sql%rowcount;

    while (change_num > 0)
    loop
      update
        snapshot_vazba
      set
        kod = v_party
      where
        po_cluid in (select po_cluid from snapshot_vazba where kod = v_party) and kod is null;

      update
        snapshot_vazba
      set
        kod = v_party
      where
        kod is null and
        fo_cluid in (select fo_cluid from snapshot_vazba where kod = v_party);

      change_num := sql%rowcount;

    end loop;

    commit;

    v_party := v_party + 1;  
    v_cluid := get_cluid;
  end loop;
end;
/

这行得通:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-27
    • 2015-10-06
    • 1970-01-01
    • 2018-06-27
    • 2017-01-21
    • 2017-07-18
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多