级联行在Oracle中复制

时间:2012-03-07 16:36:04

标签: sql oracle batch-file foreign-keys copy

我和this one有完全相同的问题,除了我在Oracle上运行而不是SQL-Server。

我有这样的结构:

[多边形

IdPolygon (Primary Key) 
VertexA 
VertexB
VertexC

[ FrontFaces

IdFace (Primary Key) 
IdPolygon (Foreign Key)
FaceValue

[ LinesGroups

IdLinesGroup (Primary Key) 
IdFace (Foreign Key)
LinesGroupValue

[

IdLine (Primary Key) 
IdLinesGroup (Foreign Key)
LineValue

[

IdPoint (Primary Key) 
IdLine (Foreign Key)
PointValue

这是一个想法:

  • 添加多边形时触发程序
  • 如果新插入的Polygon中的VertexA VertexB和VertexC与数据库中另一个现有Polygon的相同,那么我们将复制与此匹配多边形具有依赖关系的所有行:FrontFaces / LinesGroups / Lines / Points。 每个表中必须更改的唯一值是必须由sequence_name.nextVal设置的唯一主键

有没有办法在不列出所有表/行的情况下执行此操作(基于外键搜索?)

3 个答案:

答案 0 :(得分:1)

考虑这个问题:

with ri_tables as
(select parent, parent_key, child, foreign_key, min(ri_depth) as ri_depth
  from (select parent, parent_key, child, foreign_key, level as ri_depth
          from (select parent_table.table_name parent,
                       parent_constraint.constraint_name as parent_key,
                       child_table.table_name child,
                       child_constraint.constraint_name as foreign_key
                  from all_tables      parent_table
                       inner join all_constraints parent_constraint
                          on parent_table.table_name = parent_constraint.table_name
                       inner join all_constraints child_constraint
                          on child_constraint.r_constraint_name = parent_constraint.constraint_name
                       inner join all_tables      child_table
                          on child_table.table_name = child_constraint.table_name
                 where parent_constraint.constraint_type IN( 'P', 'U' )
                   and child_constraint.constraint_type   = 'R'
                   and child_table.table_name != parent_table.table_name
               )
         start with parent = 'POLYGON'
        connect by nocycle prior child = parent
        )
 group by parent, child, parent_key, foreign_key
)
select ri_tables.parent as source_table,
       pc.column_name as source_key_column,
       ri_tables.child as target_table,
       cc.column_name as target_key_column,
       pc.position as position
  from ri_tables
       inner join all_cons_columns pc
          on ri_tables.parent      = pc.table_name
         and ri_tables.parent_key  = pc.constraint_name
       inner join all_cons_columns cc
          on ri_tables.child       = cc.table_name
         and ri_tables.foreign_key = cc.constraint_name
         and pc.position           = cc.position
 order by ri_tables.ri_depth, ri_tables.parent, ri_tables.child,
          pc.position;

这将遍历外键层次结构,按顺序列出所有表依赖项,显示外键列如何链接到父项。

没有一种简单的方法可以构建所需的插入语句,而无需为正在复制数据的每个表拖拽user_tab_columns。上面的SQL至少显示了您不需要复制哪些列,而是需要使用序列值。

当然,如果你有任何多列主键或外键,任何依赖于上述SQL的代码都会完全破坏。

我认为现在是时候考虑是否需要复制所有这些数据而不是要复制所有这些数据。在关系数据库中存在重复数据通常被认为是一个坏主意。

答案 1 :(得分:0)

给出一个表的名称我终于能够检索子表和将它们连接在一起的Primarary / Foreign Key

SELECT   pk.table_name AS "Base Table", fk.table_name AS "Found Table", pc.column_name AS "Linking Key"
  FROM all_constraints pk, all_constraints fk, all_cons_columns pc, all_cons_columns fc
    WHERE pk.owner = pc.owner AND fk.owner = fc.owner 
    AND pk.constraint_name = pc.constraint_name AND fk.constraint_name = fc.constraint_name
    AND fk.r_owner = pk.owner 
    AND fk.r_constraint_name = pk.constraint_name
    AND pc.position = fc.position
    AND pk.constraint_type IN ('P', 'U')
    AND fk.constraint_type = 'R' 
    AND pk.owner = 'USER'
    AND pk.table_name = 'FRONTFACES';

我的测试基础的结果是:

  • 基本表:FRONTFACES
  • 找到表:LINESGROUPS
  • 关键字:IDFACE

但执行时间非常慢(大约8秒左右),如果有人可以帮助加快速度......

答案 2 :(得分:0)

好吧,我真的尝试自动获取外键,但是它确实在all_constraints中搜索对于生产基地来说效率不高(在我的服务器上查询8到10秒)。 所以我写下了一个程序,列出了要用游标复制的所有表/字段,以获得多行及其子项:

CREATE OR REPLACE PROCEDURE DUPLICATEFACE_PRO 
(
  POLYGONID IN NUMBER DEFAULT 1 
) AS 
-- Declare variables to hold values from table columns
-- Table FrontFaces
FrontFaces_Old_idFace FrontFaces.idFace%TYPE;
FrontFaces_New_idFace FrontFaces.idFace%TYPE;
FrontFaces_FaceValue  FrontFaces.FaceValue%TYPE;
-- Table LinesGroups
LinesGroups_Old_idLinesGroup LinesGroups.idLinesGroup%TYPE;
LinesGroups_New_idLinesGroup LinesGroups.idLinesGroup%TYPE;
LinesGroups_LinesGroupValue LinesGroups.LinesGroupValue%TYPE;
-- Table Lines
Lines_Old_idLine Lines.idLine%TYPE;
Lines_New_idLine Lines.idLine%TYPE;
Lines_LineValue Lines.LineValue%TYPE;
-- Table Points
Points_Old_idPoint Points.idPoint%TYPE;
Points_New_idPoint Points.idPoint%TYPE;
Points_PointValue Points.PointValue%TYPE;

-- Cursor to fill FrontFaces
-- Select each Face and Value Referencing POLYGONID from FrontFaces
CURSOR C1 IS select a.facevalue, a.idface
  from frontfaces a
  where a.idpolygon = POLYGONID
  AND ROWNUM = 1;

-- Cursor to fill LinesGroups
-- Select each LinesGroup and Value Referencing Old_idFace from LinesGroups
CURSOR C2 IS select a.LinesGroupValue, a.idLinesGroup
      from LinesGroups a
      where a.idFace = frontfaces_old_idface;

-- Cursor to fill Lines
-- Select each Line and Value Referencing Old_idLinesGroup from Lines
CURSOR C3 IS select a.LineValue, a.idLine
      from Lines a
      where a.idLinesGroup = linesgroups_old_idlinesgroup;

-- Cursor to fill Points
-- Select each Point and Value Referencing Old_idLine from Points
CURSOR C4 IS select a.PointValue, a.idPoint
      from Points a
      where a.idLine = lines_old_idline;

BEGIN
  OPEN C1;
  LOOP
  -- Put Select results in variables
  FETCH C1 INTO FrontFaces_FaceValue, FrontFaces_Old_idFace;
  EXIT WHEN C1%NOTFOUND;
  -- Put the next free id in a variable
  FrontFaces_New_idFace := frontfaces_seq.nextval;
  -- Create a new row with same FaceValue and Reference to POLYGONID
  INSERT INTO FrontFaces(idFace, idPolygon, FaceValue)
    VALUES(FrontFaces_New_idFace, POLYGONID, FrontFaces_FaceValue);
  dbms_output.put_line('New row with FaceValue = ' || FrontFaces_FaceValue || '  & New_Id ' || FrontFaces_New_idFace || '  & POLYGONID ' || POLYGONID);

  -- Start another Cursor to fill LinesGroups
      OPEN C2;
      LOOP
      -- Put Select results in variables
      FETCH C2 INTO LinesGroups_LinesGroupValue, LinesGroups_Old_idLinesGroup;
      EXIT WHEN C2%NOTFOUND;
      -- Put the next free id in a variable
      LinesGroups_New_idLinesGroup := linesgroups_seq.nextval;
      -- Create a new row with same LinesGroupValue and Reference to New_idFace
      INSERT INTO LinesGroups(idLinesGroup, idFace, LinesGroupValue)
        VALUES(LinesGroups_New_idLinesGroup, FrontFaces_New_idFace, LinesGroups_LinesGroupValue);
      dbms_output.put_line('New row with LinesGroupValue = ' || LinesGroups_LinesGroupValue || '  & New_Id ' || LinesGroups_New_idLinesGroup || '  & New_idFace ' || FrontFaces_New_idFace);

        -- Start another Cursor to fill Lines
        OPEN C3;
          LOOP
          -- Put Select results in variables
          FETCH C3 INTO Lines_LineValue, Lines_Old_idLine;
          EXIT WHEN C3%NOTFOUND;
          -- Put the next free id in a variable
          Lines_New_idLine := lines_seq.nextval;
          -- Create a new row with same LineValue and Reference to New_idLinesGroup
          INSERT INTO Lines(idLine, idLinesGroup, LineValue)
            VALUES(Lines_New_idLine, LinesGroups_New_idLinesGroup, Lines_LineValue);
          dbms_output.put_line('New row with LineValue = ' || Lines_LineValue || '  & New_Id ' || Lines_New_idLine || '  & New_idLinesGroup ' || LinesGroups_New_idLinesGroup);

          -- Start another Cursor to fill Lines
            OPEN C4;
              LOOP
              -- Put Select results in variables
              FETCH C4 INTO Points_PointValue, Points_Old_idPoint;
              EXIT WHEN C4%NOTFOUND;
              -- Put the next free id in a variable
              Points_New_idPoint := points_seq.nextval;
              -- Create a new row with same LineValue and Reference to New_idLinesGroup
              INSERT INTO Points(idPoint, idLine, PointValue)
                VALUES(Points_New_idPoint, Lines_New_idLine, Points_PointValue);
              dbms_output.put_line('New row with PointValue = ' || points_pointvalue || '  & New_Id ' || Points_New_idPoint || '  & New_idLine ' || Lines_New_idLine);
              END LOOP;
            CLOSE C4;

          END LOOP;
        CLOSE C3;

      END LOOP;
    CLOSE C2;

  END LOOP;
CLOSE C1;
END DUPLICATEFACE_PRO;