[英]compare data types of two table columns in oracle
考虑我有2个数据库A1和A2,它们都有相似的表,考虑A1中的T1和A2中的T2。
我需要一个sql查询来比较表中每一列的数据类型,该查询应返回与两个表中的数据类型都不匹配的列名。
这种类型的问题有一个非常漂亮且非常有效的解决方案-没有联接,没有MINUS
操作等,并且仅通过ALL_TAB_COLUMNS
可能是一个很大的表。 它是由Marco Stefanelli(如果我没记错的话)最早在几年前在AskTom上提出的,在此进行了改进,并已成为表比较的标准。
我没有两个不同的数据库可玩,所以我仅说明如何比较不同模式中的表。 您将需要适应您的情况(您可能必须从两个数据库中的USER_TAB_COLUMNS
中读取信息。)
在这种情况下,我们选择表所有者,表名称以及列名称,数据类型和其他特征; 我们使用GROUP BY
列名和所有这些列属性; 并且我们仅选择行HAVING COUNT(*) = 1
。 实际上,如果两张表中的列具有相同的名称和所有相同的特征,则计数将为2,并且输出中将没有对应的行。 仅在以下情况下,输出才会显示一行(对应于一个列名+两个或两个原始表中的属性):列名仅出现在一个表中,而不出现在另一个表中; 或者,如果列名同时出现在两个表中,但至少一个属性不同。 尝试在下面的最终输出中发现差异!
如您所见,在解决方案中,我需要选择max(owner)
和max(table_name)
-因为我不按这些列进行分组-但实际上我只选择了只有一行的组,因此max()
确实没有任何作用。
设置:我在自己的“沙盒”(我为自己创建的架构,称为INTRO
)中从SCOTT
架构复制了EMP
表。 我使用CTAS创建副本-这将复制所有列名和数据类型(视情况包括大小/精度/小数位数),但是例如,它不会复制“非空”约束。 因此,我包括了ALL_TAB_COLUMNS
的nullable
为nullable
列,以捕获此类差异。 通过使用“始终为假”的WHERE
过滤器,我仅选择表结构,而不选择数据。
create table empl as select * from scott.emp where 0 is null;
Table EMPL created.
alter table empl drop column comm;
Table EMPL altered.
alter table empl add sex char(1);
Table EMPL altered.
alter table empl modify job varchar2(20);
Table EMPL altered.
alter table empl modify deptno not null;
Table EMPL altered.
所以现在我有:
describe scott.emp
Name Null Type
-------- -------- ------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
describe intro.empl
Name Null Type
-------- -------- ------------
EMPNO NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(20)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
DEPTNO NOT NULL NUMBER(2)
SEX CHAR(1)
解决方案 (查询以比较两个表):
select max(owner) as owner, max(table_name) as table_name,
column_name, data_type, data_length, data_precision, data_scale, nullable
from all_tab_columns
where (owner = 'SCOTT' and table_name = 'EMP')
or (owner = 'INTRO' and table_name = 'EMPL')
group by column_name, data_type, data_length, data_precision, data_scale, nullable
having count(*) = 1
order by column_name, owner, table_name;
输出 :
OWNER TABLE_NAME COLUMN_NAME DATA_TYPE DATA_LENGTH DATA_PRECISION DATA_SCALE NULLABLE
----- ---------- ----------- --------- ----------- -------------- ---------- --------
SCOTT EMP COMM NUMBER 22 7 2 Y
INTRO EMPL DEPTNO NUMBER 22 2 0 N
SCOTT EMP DEPTNO NUMBER 22 2 0 Y
INTRO EMPL EMPNO NUMBER 22 4 0 Y
SCOTT EMP EMPNO NUMBER 22 4 0 N
INTRO EMPL JOB VARCHAR2 20 Y
SCOTT EMP JOB VARCHAR2 9 Y
INTRO EMPL SEX CHAR 1 Y
如果需要将一个表与另一个表进行比较,以查找名称相同但类型不同的列,则可以使用以下内容。
设定:
create table t1(a number, b varchar2(16), c date, d clob);
create table t2(a number, b varchar2(99), c timestamp, d clob);
查询:
select db1.column_name, db1.table_name, db2.table_name
from all_tab_columns db1
inner join all_tab_columns db2
on (db1.owner = db2.owner
and db1.column_name = db2.column_name)
where db1.table_name = 'T1'
and db2.table_name = 'T2'
and (
db1.data_type != db2.data_type
OR db1.data_length != db2.data_length
)
COLUMN_NAME TABLE_NAME TABLE_NAME
-------------------------- -------------------------- --------------------------
B T1 T2
C T1 T2
这将检查同一数据库上的表; 要在两个数据库之间使用它,您应该具有从一个实例到另一个实例的dblink,并用all_tab_columns@yourDBLink
替换一次出现的all_tab_columns
。
请注意,这仅考虑两个表上存在的名称相同但类型不同的列; 这将无法处理名称不同的列或仅存在于一个表中的列的情况
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.