查询数据库中所有表的数据量、有效数据量以及其它定制数据量

 
经常会遇到类似的需求,有时不只是要有效,也有可能要今年的,或其它什么样的数据

最基础的办法是手动一个一个写。比如:
SQL code
?
1
2
3
SELECT COUNT(1) FROM A  
SELECT COUNT(1)  FROM B  
SELECT COUNT(1)  FROM C  

上面这种写法,在查询客户端里跑的时候,会返回N个查询结果,看起来比较麻烦,而且拖到下边会不知道这个结果是哪个表的。

我通常的写法,是在查询列中加一列常量,然后用UNION ALL将结果集合并为一个,就像下面的格式:
SQL code?
1
2
3
SELECT 'A' AS TB,COUNT(1) AS TOTAL FROM UNION ALL  
SELECT 'B',COUNT(1) FROM UNION ALL  
SELECT 'C',COUNT(1) FROM 
  
这样会写会返回一个两列的结果集,列名和对应的数量都有。但这只是开始。


由于数据库中的表可能会添加、改名、删除,你的语句也就得跟着变,如果数据库开发人员比较无脑(大部分时候这个人就是你),语句变动的频率也会很快,所以懒惰的我想要一直用一个不变的语句查询。这时需要用到系统表了,有两个表可以用,一个是SYS.TABLES,一个是INFORMATION_SCHEMA.TABLES。前者返回当前库中所有用户表,后者返回所有用户表和视图,实际我们只需要里面的表名列来生成我们的查询语句。我一般使用前者。先来一个简单一点的
SQL code
?
1
2
SELECT 'UNION ALL SELECT '''+NAME+''' AS TB,COUNT(1) AS TOTAL FROM ['+NAME+']'  
FROM SYS.TABLES 

如上,把查询结果全部复制到新的查询窗口里,再删掉第一个"UNION ALL ",就是生成好的查询语句了,你可以在任何时候用这两步来生成你需要的查询语句,不用管表变了多少。

但懒人还是觉得麻烦,因为要复制出来,还要删字符串,还要再运行一次。所以我会再加上几句,把这几步也省掉。
SQL code
?
1
2
3
4
5
DECLARE @SQL VARCHAR(MAX)  
SELECT @SQL=ISNULL(@SQL+'  
UNION ALL ','')+'SELECT '''+NAME+''' AS TB,COUNT(1) AS TOTAL FROM ['+NAME+']'  
FROM SYS.TABLES  
EXEC (@SQL)  


一次运行就出结果,方便快捷。喜欢的同学可以存起来。但这也只是开始


-----------------------------------------------------木有分割线的文章不是好文章-------------------------------------------------------------------


在使用了系统表、字符串拼接、动态SQL执行后,我们可以不关注表名查询库中所有表的数据量了,但万恶的业务人员或万万恶的BOSS会提出更过分的要求,比如要有效的,要今年的。下面我就以这几个现在能想到的需求为例,扩展一下上面的语句,让它更强大:

首先我们假设库中有一部分表,区分有效和无效的状态位为STATE,1为有效,0为无效。另有一部分表中有CREATE_TIME列,存创建日期,又有一部分表中有INPUT_TIME,也是存创建日期,这两部分表有交集。按这种需求,写好的SQL语句如下:
SQL code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
DECLARE @SQL VARCHAR(MAX)  
SELECT @SQL=ISNULL(@SQL+'  
UNION ALL ','')+'SELECT '''+T1.NAME+''' AS TB,COUNT(1) AS TOTAL,'+  
CASE WHEN T2.NAME IS NOT NULL THEN 'SUM(CASE WHEN STATE=1 THEN 1 ELSE 0 END)' ELSE 'NULL' END+  
' AS STATE,'+  
CASE WHEN T3.NAME IS NOT NULL THEN 'SUM(CASE WHEN YEAR(CREATE_TIME)=YEAR(GETDATE()) THEN 1 ELSE 0 END)'  
ELSE 'NULL' END+  
' AS CREATE_TIME,'+  
CASE WHEN T4.NAME IS NOT NULL THEN 'SUM(CASE WHEN YEAR(INPUT_TIME)=YEAR(GETDATE()) THEN 1 ELSE 0 END)'  
ELSE 'NULL' END+  
' AS INPUT_TIME FROM ['+T1.NAME+']'  
FROM SYS.TABLES T1  
LEFT JOIN (  
SELECT OBJECT_NAME(OBJECT_ID) AS NAME FROM SYS.COLUMNS WHERE NAME='STATE'  
) T2 ON T1.NAME=T2.NAME  
LEFT JOIN (  
SELECT OBJECT_NAME(OBJECT_ID) AS NAME FROM SYS.COLUMNS WHERE NAME='CREATE_TIME'  
) T3 ON T1.NAME=T3.NAME  
LEFT JOIN (  
SELECT OBJECT_NAME(OBJECT_ID) AS NAME FROM SYS.COLUMNS WHERE NAME='INPUT_TIME'  
) T4 ON T1.NAME=T4.NAME  
EXEC (@SQL)  


结果自己运行就知道了,这个SQL唯一的BUG是,如果STATE,CREATE_TIME,INPUT_TIME不是对应的类型,可能会报转换错误,这可以通过关联SYS.TYPES表确认字段类型避免。但考虑到我已经声明了我是个懒人,所以决定不写了。


上面的SQL,已经基本体现出了动态查询的强大之处,你可以通过关联数据字典和拼接字符串,生成你想要的任意条件的查询语句,如果你在查询SYS.TABLES时加入了条件,那也就实现了查询特定部分表的功能。基本上,只要一次写好,后面查询的时候你都可以把语句复制进去以后枕着双手惬意的看着服务器忙活而不用再手忙脚乱的调试语句中的错误了。

BLOG地址:
http://blog.csdn.net/guguda2008/article/details/7718367
posted @ 2014-03-20 16:00  xyzhuzhou  阅读(829)  评论(0编辑  收藏  举报