比较oracle中两个表列的数据类型

时间:2016-10-19 11:58:25

标签: sql oracle

考虑我有2个数据库A1和A2,两个都有类似的表,考虑A1中的T1和A2中的T2。

我需要一个sql查询来比较表中每列的数据类型,查询应返回与两个表中的数据类型不匹配的列名。

2 个答案:

答案 0 :(得分:2)

This type of problem has a beautiful and very efficient solution - no joins, no MINUS operations etc., and only one pass over ALL_TAB_COLUMNS, which may be a very large table. It was first proposed by Marco Stefanelli (if I remember the name correctly) on AskTom several years ago, it was refined there and it has become the standard for table comparisons.

I don't have two different databases to play with, so I will just illustrate how I can compare tables in different schemas. You will need to adapt for your situation (you may have to read from USER_TAB_COLUMNS in both databases.)

In this case, we select table owner, table name, and column names, data types and other characteristics; we GROUP BY column name and all those column properties; and we select only the rows HAVING COUNT(*) = 1. Indeed, if a column has the same name AND all the same characteristics in both tables, then the count will be 2 and there will be no corresponding row in the output. The output will show a row (corresponding to a column name + properties in one or both of the original tables) only if: the column name appears only in one table but not in the other; OR if the column name appears in both tables but at least one of the properties is different. Try to spot the differences in the final output below!

As you will see, in the solution I need to select max(owner) and max(table_name) - since I don't group by those columns - but in fact I select only the groups that have exactly one row, so the max() really has no effect.

Setup: I make a copy of the EMP table from the SCOTT schema in my own "sandbox" (a schema I created for myself, named INTRO). I create the copy with a CTAS - this will copy all the column names and datatypes (including size/precision/scale as the case may be), but for example it does NOT copy 'not null' constraints. So I include the nullable column from ALL_TAB_COLUMNS to catch such differences. I select only the table structure, no data, by using an "always false" WHERE filter.

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.

So now I have:

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)

Solution (query to compare the two tables):

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;

Output:

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

答案 1 :(得分:0)

如果您需要将表与另一个表进行比较,查找具有相同名称但类型不同的列,则可以使用以下内容。

<强>设置:

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

检查同一个DB上的表;要在两个数据库中使用它,您应该有一个从一个实例到另一个实例的dblink,并用all_tab_columns替换一次all_tab_columns@yourDBLink

请注意,这只考虑两个表中存在的名称相同但类型不同的列; thi不会处理具有不同名称的列或仅存在于一个表中的列的情况