数据库架构(源和目标)非常大(每个数据库都有350多个表)。我已经完成了将这两个表合并为一个的任务。数据本身(表中的内容)必须迁移。我必须小心,在合并架构之前或合并架构时,主键没有重复输入。有没有人做过这样的事情并且能够向我提供他的解决方案,或者有人可以帮助我找到完成任务的方法吗?我的方法都失败了,我的顾问告诉我要在线获得帮助:/
对我来说:我尝试使用“ all_constraints”表从数据库中获取所有pk。
SELECT cols.table_name, cols.column_name, cols.position, cons.status, cons.owner
FROM all_constraints cons, all_cons_columns cols
WHERE cols.owner = 'DB'
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position;
我也“知道”主键必须有序列才能为其添加值:
CREATE SEQUENCE seq_pk_addition
MINVALUE 1
MAXVALUE 99999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
因为如果涉及pl / sql(或一般来说是sql,我是菜鸟,那么下一步我应该怎么做? :/
这里是数据库的ERD的链接:https://ufile.io/9tdoj
正如我的评论所承诺的那样,我准备了一个动态代码,您可以尝试使用该代码获取源表和目标表的数据merged
。逻辑如下:
Step1:从SOURCE
模式中获取所有表名。在下面的查询中,您可能需要分别替换架构(所有者)名称。为了进行测试,我只使用了1张表,因此在运行它时,请删除表名筛选子句。
Step2:获取表的约束列名称。这用于准备ON
子句,该子句稍后将用于MERGE
语句。
Step3:获取表的不受限制的列名。使用UPDATE
时,将在MERGE
子句中使用。
Step4:当数据与insert
语句的ON
条件不匹配时,准备MERGE
列表。
阅读我的内联注释以了解每个步骤。
CREATE OR REPLACE PROCEDURE COPY_TABLE
AS
Type OBJ_NME is table of varchar2(100) index by pls_integer;
--To hold Table name
v_obj_nm OBJ_NME ;
--To hold Columns of table
v_col_nm OBJ_NME;
v_othr_col_nm OBJ_NME;
on_clause VARCHAR2(2000);
upd_clause VARCHAR2(4000);
cntr number:=0;
v_sql VARCHAR2(4000);
col_list1 VARCHAR2(4000);
col_list2 VARCHAR2(4000);
col_list3 VARCHAR2(4000);
col_list4 varchar2(4000);
col_list5 VARCHAR2(4000);
col_list6 VARCHAR2(4000);
col_list7 VARCHAR2(4000);
col_list8 varchar2(4000);
BEGIN
--Get Source table names
SELECT OBJECT_NAME
BULK COLLECT INTO v_obj_nm
FROM all_objects
WHERE owner LIKE 'RU%' -- Replace `RU%` with your Source schema name here
AND object_type = 'TABLE'
and object_name ='TEST'; --remove this condition if you want this to run for all tables
FOR I IN 1..v_obj_nm.count
loop
--Columns with Constraints
SELECT column_name
bulk collect into v_col_nm
FROM user_cons_columns
WHERE table_name = v_obj_nm(i);
--Columns without Constraints remain columns of table
SELECT *
BULK COLLECT INTO v_othr_col_nm
from (
SELECT column_name
FROM user_tab_cols
WHERE table_name = v_obj_nm(i)
MINUS
SELECT column_name
FROM user_cons_columns
WHERE table_name = v_obj_nm(i));
--Prepare Update Clause
FOR l IN 1..v_othr_col_nm.count
loop
cntr:=cntr+1;
upd_clause := 't1.'||v_othr_col_nm(l)||' = t2.' ||v_othr_col_nm(l);
upd_clause:=upd_clause ||' and ' ;
col_list1:= 't1.'||v_othr_col_nm(l) ||',';
col_list2:= col_list2||col_list1;
col_list5:= 't2.'||v_othr_col_nm(l) ||',';
col_list6:= col_list6||col_list5;
IF (cntr = v_othr_col_nm.count)
THEN
--dbms_output.put_line('YES');
upd_clause:=rtrim(upd_clause,' and');
col_list2:=rtrim( col_list2,',');
col_list6:=rtrim( col_list6,',');
END IF;
dbms_output.put_line(col_list2||col_list6);
--dbms_output.put_line(upd_clause);
End loop;
--Update caluse ends
cntr:=0; --Counter reset
--Prepare ON clause
FOR k IN 1..v_col_nm.count
loop
cntr:=cntr+1;
--dbms_output.put_line(v_col_nm.count || cntr);
on_clause := 't1.'||v_col_nm(k)||' = t2.' ||v_col_nm(k);
on_clause:=on_clause ||' and ' ;
col_list3:= 't1.'||v_col_nm(k) ||',';
col_list4:= col_list4||col_list3;
col_list7:= 't2.'||v_col_nm(k) ||',';
col_list8:= col_list8||col_list7;
IF (cntr = v_col_nm.count)
THEN
--dbms_output.put_line('YES');
on_clause:=rtrim(on_clause,' and');
col_list4:=rtrim( col_list4,',');
col_list8:=rtrim( col_list8,',');
end if;
dbms_output.put_line(col_list4||col_list8);
-- ON clause ends
--Prepare merge Statement
v_sql:= 'MERGE INTO '|| v_obj_nm(i)||' t1--put target schema name before v_obj_nm
USING (SELECT * FROM '|| v_obj_nm(i)||') t2-- put source schema name befire v_obj_nm here
ON ('||on_clause||')
WHEN MATCHED THEN
UPDATE
SET '||upd_clause ||
' WHEN NOT MATCHED THEN
INSERT
('||col_list2||','
||col_list4||
')
VALUES
('||col_list6||','
||col_list8||
')';
dbms_output.put_line(v_sql);
execute immediate v_sql;
end loop;
End loop;
END;
/
执行:
exec COPY_TABLE
输出:
anonymous block completed
PS:我已经用一个具有2列的表对其进行了测试,其中我有唯一的键约束。表的DDL如下:
最后,我希望您能理解我的代码(如果您是菜鸟),并且如果以上情况无法满足您的要求,请执行类似的操作。
CREATE TABLE TEST
( COL2 NUMBER,
COLUMN1 VARCHAR2(20 BYTE),
CONSTRAINT TEST_UK1 UNIQUE (COLUMN1)
) ;
[噢,亲爱的!通常,这样的问题会因为“范围太广”而很快结束,但是我们需要支持邪恶顾问的受害者!
至于这项工作,我需要一个星期的全职时间来聘请经验丰富的专家,还要花两天的时间对经验丰富的质量检查工程师进行质量检查。
首先,无法进行如此复杂的数据合并。这意味着您将需要可以轻松重建的两个模式的测试副本。而且您将需要一个地方来尝试一下。通常,这是通过导出两个模式和一个空的dev数据库来完成的。
接下来,您需要两个架构都足够接近才能比较数据。我可以通过导入上面提到的导出文件来实现。如果架构名称相同,则在导入期间重命名一个。
接下来,我会通过类似的查询仔细检查结构是否真的相同
SELECT a.owner, a.table_name, b.owner, b.table_name
FROM all_tables a
FULL JOIN all_tables b
ON a.table_name = b.table_name
AND a.owner = 'SCHEMAA'
AND b.owner = 'SCHEMAB'
WHERE a.owner IS NULL or b.owner IS NULL;
接下来,我将检查主键和唯一键是否重叠:
SELECT id FROM schemaa.table1
INTERSECT
SELECT id FROM schemab.table1;
由于有300多个表,我将生成这些查询:
DECLARE
stmt VARCHAR2(30000);
n NUMBER;
schema_a CONSTANT VARCHAR2(128 BYTE) := 'SCHEMAA';
schema_b CONSTANT VARCHAR2(128 BYTE) := 'SCHEMAB';
BEGIN
FOR c IN (SELECT owner, constraint_name, table_name,
(SELECT LISTAGG(column_name,',') WITHIN GROUP (ORDER BY position)
FROM all_cons_columns c
WHERE s.owner = c.owner
AND s.constraint_name = c.constraint_name) AS cols
FROM all_constraints s
WHERE s.constraint_type IN ('P')
AND s.owner = schema_a)
LOOP
dbms_output.put_line('Checking pk '||c.constraint_name||' on table '||c.table_name);
stmt := 'SELECT count(*) FROM '||schema_a||'.'||c.table_name
||' JOIN '||schema_b||'.'||c.table_name
|| ' USING ('||c.cols||')';
--dbms_output.put_line('Query '||stmt);
EXECUTE IMMEDIATE stmt INTO n;
dbms_output.put_line('Found '||n||' overlapping primary keys in table '||c.table_name);
END LOOP;
END;
/
首先,对于350个表,最有可能需要dynamic SQL
。
CURSOR
或COLLECTION - table of VARCHAR2
。dynamic SQL
。loop
遍历表名的整个列表,并为每个表生成一个字符串,将使用EXECUTE IMMEDIATE
命令将其作为SQL执行。