考虑我有2个数据库A1和A2,两个都有类似的表,考虑A1中的T1和A2中的T2。
我需要一个sql查询来比较表中每列的数据类型,查询应返回与两个表中的数据类型不匹配的列名。
答案 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不会处理具有不同名称的列或仅存在于一个表中的列的情况