元数据查询
1、列出模式中的所有表
问题:你想列出自己在给定模式中创建的所有表。
解决方案:下面的所有解决方案都假设你使用的模式为 SMEAGOL。在所有 RDBMS 中,解决方案采用的基本方法都相同------查询系统表(视图)。对于数据库中的每张表,这个系统表(视图)都包含一行与之相关的信息。
DB2:查询 SYSCAT.TABLES。
sql
select tabname
from syscat.tables
where tabschema = 'SMEAGOL';
Oracle:查询 SYS.ALL_TABLES。
sql
select table_name
from all_tables
where owner = 'SMEAGOL';
查询 INFORMATION_SCHEMA.TABLES。
sql
select table_name
from information_schema.tables
where table_schema = 'SMEAGOL'
暴露有关自己的信息时,数据库使用的正是你为自己的应用程序创建的机制------表和视图,这有点儿循环的"味道"。例如,Oracle 维护着一个庞大的系统视图(如ALL_TABLES)目录,你可以通过查询这些视图来获取有关表、索引、授权(grant)和其他数据库对象的信息。
Oracle 的目录视图仅仅是视图。它们基于一组底层表,这些底层表包含的信息不便于用户读取。这些视图让用户能够轻松地使用Oracle 的目录数据。
Oracle 系统视图和 DB2 系统表都是厂商专用的,而PostgreSQL、MySQL 和 SQL Server 支持信息模式------ISO SQL 标准定义的一组视图,因此有些查询适用于这 3种 RDBMS。
2、列出表中的列
问题:你想列出表中的列,以及这些列的数据类型和在表中的位置。
解决方案:下面的解决方案假设你要列出模式 SMEAGOL 中 EMP 表的列及其数据类型和用数字表示的位置。
DB2:查询 SYSCAT.COLUMNS。
sql
select colname, typename, colno
from syscat.columns
where tabname = 'EMP'
and tabschema = 'SMEAGOL'
Oracle:查询 ALL_TAB_COLUMNS。
sql
select column_name, data_type, column_id
from all_tab_columns
where owner = 'SMEAGOL'
and table_name = 'EMP'
PostgreSQL、MySQL 和 SQL Server:查询 INFORMATION_SCHEMA.COLUMNS。
sql
select column_name, data_type, ordinal_position
from information_schema.columns
where table_schema = 'test'
and table_name = 'emp';
3、列出表的索引列
问题:你想列出给定表的索引、索引基于的列以及这些列在索引中的位置(如果有的话)。
解决方案:下面的解决方案随 RDBMS 而异,但假设你要列出模式SMEAGOL 中 EMP 表的索引。
DB2:查询 SYSCAT.INDEXES。
sql
select a.tabname, b.indname, b.colname, b.colseq
from syscat.indexes a,syscat.indexcoluse b
where a.tabname = 'EMP'
and a.tabschema = 'SMEAGOL'
and a.indschema = b.indschema
and a.indname = b.indname
Oracle:查询 SYS.ALL_IND_COLUMNS。
sql
select table_name, index_name, column_name, column_position
from sys.all_ind_columns
where table_name = 'EMP'
and table_owner = 'SMEAGOL'
PostgreSQL:查询 PG_CATALOG.PG_INDEXES 和INFORMATION_SCHEMA.COLUMNS。
sql
select a.tablename,a.indexname,b.column_name
from pg_catalog.pg_indexes a,information_schema.columns b
where a.schemaname = 'SMEAGOL'
and a.tablename = b.table_name
MySQL:使用命令 SHOW INDEX。
sql
show index from emp;
SQL Server:查询 SYS.TABLES、SYS.INDEXES、SYS.INDEX_COLUMNS 和 SYS.COLUMNS。
sql
select a.name table_name,
b.name index_name,
d.name column_name,
c.index_column_id
from sys.tables a,
sys.indexes b,
sys.index_columns c,
sys.columns d
where a.object_id = b.object_id
and b.object_id = c.object_id
and b.index_id = c.index_id
and c.object_id = d.object_id
and c.column_id = d.column_id
and a.name = 'EMP'
4、列出表的约束
问题:你想列出给表定义的约束以及这些约束是在哪些列上定义的。例如,你想获悉 EMP 表的约束以及这些约束是在哪些列上定义的。
解决方案:
DB2:查询 SYSCAT.TABCONST 和 SYSCAT.COLUMNS。
sql
select a.tabname, a.constname, b.colname, a.type
from syscat.tabconst a,syscat.columns b
where a.tabname = 'EMP'
and a.tabschema = 'SMEAGOL'
and a.tabname = b.tabname
and a.tabschema = b.tabschema
Oracle:查询 SYS.ALL_CONSTRAINTS 和SYS.ALL_CONS_COLUMNS。
sql
select a.table_name,
a.constraint_name,
b.column_name,
a.constraint_type
from all_constraints a,all_cons_columns b
where a.table_name = 'EMP'
and a.owner = 'SMEAGOL'
and a.table_name = b.table_name
and a.owner = b.owner
and a.constraint_name = b.constraint_name
PostgreSQL、MySQL 和 SQL Server:查询 INFORMATION_SCHEMA.TABLE_CONSTRAINTS和 INFORMATION_SCHEMA.KEY_COLUMN_USAGE。
sql
select a.table_name,
a.constraint_name,
b.column_name,
a.constraint_type
from information_schema.table_constraints a, information_schema.key_column_usage b
where a.table_name = 'emp'
and a.table_schema = 'test'
and a.table_name = b.table_name
and a.table_schema = b.table_schema
and a.constraint_name = b.constraint_name;
5、列出没有相应索引的外键
问题:你想列出没有相应索引的外键,例如,你想知道是否在EMP 表的外键上创建了索引。
解决方案:
`DB2查询 SYSCAT.TABCONST、SYSCAT.KEYCOLUSE、SYSCAT.INDEXES 和 SYSCAT.INDEXCOLUSE。
sql
select fkeys.tabname,
fkeys.constname,
fkeys.colname,
ind_cols.indname
from (
select a.tabschema, a.tabname, a.constname, b.colname
from syscat.tabconst a,
syscat.keycoluse b
where a.tabname = 'EMP'
and a.tabschema = 'SMEAGOL'
and a.type = 'F'
and a.tabname = b.tabname
and a.tabschema = b.tabschema
) fkeys
left join
(
select a.tabschema,
a.tabname,
a.indname,
b.colname
from syscat.indexes a,
syscat.indexcoluse b
where a.indschema = b.indschema
and a.indname = b.indname
) ind_cols
on (fkeys.tabschema = ind_cols.tabschema
and fkeys.tabname = ind_cols.tabname
and fkeys.colname = ind_cols.colname )
where ind_cols.indname is null
Oracle:查询 SYS.ALL_CONS_COLUMNS、SYS.ALL_CONSTRAINTS 和SYS.ALL_IND_COLUMNS。
sql
select a.table_name,
a.constraint_name,
a.column_name,
c.index_name
from all_cons_columns a,
all_constraints b,
all_ind_columns c
where a.table_name = 'EMP'
and a.owner = 'SMEAGOL'
and b.constraint_type = 'R'
and a.owner = b.owner
and a.table_name = b.table_name
and a.constraint_name = b.constraint_name
and a.owner = c.table_owner (+)
and a.table_name = c.table_name (+)
and a.column_name = c.column_name (+)
and c.index_name is null
查询 INFORMATION_SCHEMA.KEY_COLUMN_USAGE、INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS、INFORMATION_SCHEMA.COLUMNS 和PG_CATALOG.PG_INDEXES。
sql
select fkeys.table_name,
fkeys.constraint_name,
fkeys.column_name,
ind_cols.indexname
from (
select a.constraint_schema,
a.table_name,
a.constraint_name,
a.column_name
from information_schema.key_column_usage a,
information_schema.referential_constraints b
where a.constraint_name = b.constraint_name
and a.constraint_schema = b.constraint_schema
and a.constraint_schema = 'SMEAGOL'
and a.table_name = 'EMP'
) fkeys
left join
(
select a.schemaname, a.tablename, a.indexname, b.column_name
from pg_catalog.pg_indexes a,
information_schema.columns b
where a.tablename = b.table_name
and a.schemaname = b.table_schema
) ind_cols
on ( fkeys.constraint_schema = ind_cols.schemaname
and fkeys.table_name = ind_cols.tablename
and fkeys.column_name = ind_cols.column_name )
where ind_cols.indexname is null select fkeys.table_name,
fkeys.constraint_name,
fkeys.column_name,
ind_cols.indexname
from (
select a.constraint_schema,
a.table_name,
a.constraint_name,
a.column_name
from information_schema.key_column_usage a,
information_schema.referential_constraints b
where a.constraint_name = b.constraint_name
and a.constraint_schema = b.constraint_schema
and a.constraint_schema = 'SMEAGOL'
and a.table_name = 'EMP'
) fkeys
left join
(
select a.schemaname, a.tablename, a.indexname, b.column_name
from pg_catalog.pg_indexes a,
information_schema.columns b
where a.tablename = b.table_name
and a.schemaname = b.table_schema
) ind_cols
on ( fkeys.constraint_schema = ind_cols.schemaname
and fkeys.table_name = ind_cols.tablename
and fkeys.column_name = ind_cols.column_name )
where ind_cols.indexname is null
MySQL:可以使用命令 SHOW INDEX 来检索索引信息,比如索引的名称、索引包含的列,以及这些列在索引中的序数位置。另外,可以通过查询INFORMATION_SCHEMA.KEY_COLUMN_USAGE 来列出给定表的外键。在 MySQL 5 中,据说会自动在外键上创建索引,但实际上可能被删除。要确定外键列对应的索引是否被删除了,可以执行命令 SHOW INDEX,并将其输出同查询INFORMATION_SCHEMA.KEY_COLUMN_USAGE.COLUMN_NAME 的结果进行比较。如果 COLUMN_NAME 包含在KEY_COLUMN_USAGE 中,但命令 SHOW INDEX 没有返回它,那么便可确定没有在该列上创建索引。
SQL Server:查询 SYS.TABLES、SYS.FOREIGN_KEYS、SYS.COLUMNS、SYS.INDEXES 和SYS.INDEX_COLUMNS。
sql
select fkeys.table_name,
fkeys.constraint_name,
fkeys.column_name,
ind_cols.index_name
from (
select a.object_id,
d.column_id,
a.name table_name,
b.name constraint_name,
d.name column_name
from sys.tables a
join
sys.foreign_keys b
on ( a.name = 'EMP'
and a.object_id = b.parent_object_id
)
join
sys.foreign_key_columns c
on ( b.object_id = c.constraint_object_id )
join
sys.columns d
on ( c.constraint_column_id = d.column_id
and a.object_id = d.object_id
)
) fkeys
left join
(
select a.name index_name,
b.object_id,
b.column_id
from sys.indexes a,
sys.index_columns b
where a.index_id = b.index_id
) ind_cols
on ( fkeys.object_id = ind_cols.object_id
and fkeys.column_id = ind_cols.column_id )
where ind_cols.index_name is null
6、使用SQL生成SQL
问题:你想创建动态 SQL 语句,目的可能是要自动执行维护任务。具体地说,你要完成 3 项任务:计算表中的行数,禁用给表定义的外键约束,根据表中的数据生成插入脚本。
解决方案:使用字符串来创建 SQL 语句,对于其中需要填入的值(比如命令针对的对象的名称)将由来自表的数据提供。别忘了,这里的查询只生成语句,你必须通过脚本(或其他执行 SQL 语句的方式)手动执行它们。下面的解决方案适用于 Oracle 系统,对于其他 RDBMS,采用的方法完全相同,唯一不同的是数据字典的名称和日期格式等。下面显示的输出是在我的笔记本计算机的 Oracle 实例中执行这些查询时得到的,你执行这些查询时,返回的结果集肯定不一样。
sql
/* 生成计算所有表中行数的SQL */
select 'select count(*) from '||table_name||';' cnts
from user_tables;
CNTS
----------------------------------------
select count(*) from ANT;
select count(*) from BONUS;
select count(*) from DEMO1;
select count(*) from DEMO2;
select count(*) from DEPT;
select count(*) from DUMMY;
select count(*) from EMP;
select count(*) from EMP_SALES;
select count(*) from EMP_SCORE;
select count(*) from PROFESSOR;
select count(*) from T;
select count(*) from T1;
select count(*) from T2;
select count(*) from T3;
select count(*) from TEACH;
select count(*) from TEST;
select count(*) from TRX_LOG;
select count(*) from X;
/* 禁用所有表中定义的外键约束 */
select 'alter table '||table_name||
' disable constraint '||constraint_name||';' cons
from user_constraints
where constraint_type = 'R';
CONS
------------------------------------------------
alter table ANT disable constraint ANT_FK;
alter table BONUS disable constraint BONUS_FK;
alter table DEMO1 disable constraint DEMO1_FK;
alter table DEMO2 disable constraint DEMO2_FK;
alter table DEPT disable constraint DEPT_FK;
alter table DUMMY disable constraint DUMMY_FK;
alter table EMP disable constraint EMP_FK;
alter table EMP_SALES disable constraint EMP_SALES_FK;
alter table EMP_SCORE disable constraint EMP_SCORE_FK;
alter table PROFESSOR disable constraint PROFESSOR_FK;
/* 根据EMP表的一些列生成插入脚本 */
select 'insert into emp(empno,ename,hiredate) '||chr(10)||
'values( '||empno||','||''''||ename
||''',to_date('||''''||hiredate||''') );' inserts
from emp
where deptno = 10;
INSERTS
--------------------------------------------------
insert into emp(empno,ename,hiredate)
values( 7782,'CLARK',to_date('09-JUN-2006 00:00:00') );
insert into emp(empno,ename,hiredate)
values( 7839,'KING',to_date('17-NOV-2006 00:00:00') );
insert into emp(empno,ename,hiredate)
values( 7934,'MILLER',to_date('23-JAN-2007 00:00:00') );
7、描述Oracle数据库中的数据字典视图
问题:你使用的是 Oracle,但不记得有哪些数据字典视图可供你使用,更不记得这些视图的列定义。雪上加霜的是,你还无法访问 Oracle 文档。
解决方案这是一个专门针对 Oracle 的实例。Oracle 不仅维护着一组健壮的数据字典视图,还提供了包含数据字典视图文档的数据字典视图。这真是完美的循环引用。
查询视图 DICTIONARY,列出各个数据字典视图及其用途。
sql
select table_name, comments
from dictionary
order by table_name;
TABLE_NAME COMMENTS
------------------------------ --------------------------------------------
ALL_ALL_TABLES Description of all object and relational
tables accessible to the user
ALL_APPLY Details about each apply process that
dequeues from the queue visible to the
current user
...
查询视图 DICT_COLUMNS,获取有关给定数据字典视图包含的列的描述。
sql
select column_name, comments
from dict_columns
where table_name = 'ALL_TAB_COLUMNS';
COLUMN_NAME COMMENTS
------------------------------- --------------------------------------------
OWNER
TABLE_NAME Table, view or cluster name
COLUMN_NAME Column name
DATA_TYPE Datatype of the column
DATA_TYPE_MOD Datatype modifier of the column
DATA_TYPE_OWNER Owner of the datatype of the column
DATA_LENGTH Length of the column in bytes
DATA_PRECISION Length: decimal digits (NUMBER) or binary
digits (FLOAT)