Копирование каскадных строк в Oracle - PullRequest
0 голосов
/ 07 марта 2012

У меня точно такая же проблема, как у этого , за исключением того, что я работаю на Oracle, а не на SQL-сервере.

У меня есть такая структура:

[ Полигоны ]

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

Вот идея:

  • Запуск процедуры при добавлении многоугольника
  • , если VertexA VertexB и VertexC во вновь вставленном многоугольнике такие же, как и у другого существующего многоугольника в базе данных, мы дублируем все строки, имеющие зависимости, с этим совпадающим многоугольником: FrontFaces / LinesGroups / Lines / Точки.Единственное значение, которое должно измениться в каждой таблице, - это уникальный первичный ключ, который должен быть установлен в sequence_name.nextVal

. Есть ли способ сделать это без перечисления всех таблиц / строк (на основе поиска внешних ключей?)

Ответы [ 3 ]

1 голос
/ 09 марта 2012

Рассмотрим этот запрос:

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, полностью сломался бы.

Я думаю, что пришло время подумать, НУЖНО ли вам дублировать все эти данные по сравнению с ХОТИТЕ дублировать все эти данные. Наличие дублирующих данных в реляционных базах данных обычно считается плохой идеей.

0 голосов
/ 12 марта 2012

Ну, я действительно пытался автоматически получить внешний ключ, но похоже, что поиск в 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;
0 голосов
/ 09 марта 2012

Давая имя таблице, я наконец смог получить дочернюю таблицу и первичный / внешний ключ, связав их вместе

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 секунд или около того), если кто-нибудь может помочь ускорить его ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...