在大型系统的表结构设计中,可能所有层级子表都会冗余根级主表的记录,这样在后续使用某一条根表相关数据时,只需要一个条件过滤即可。但是如果新人或因为某些不可控原因,导致这个冗余列索引缺失,这会对后续数据使用带来很大影响。如何知道哪些有这个字段的表没有创建索引呢?下面给出了解决办法!
一、创建函数
USE tempdb
GO
IF OBJECT_ID ('dbo.PR_QUERY_COL_INDEX_LOST') IS NOT NULL
DROP PROCEDURE dbo.PR_QUERY_COL_INDEX_LOST
GO
CREATE PROCEDURE PR_QUERY_COL_INDEX_LOST(
@dbname_prefix VARCHAR(300), --数据库前缀名
@col_name VARCHAR(300) --字段名
)
AS
BEGIN
DECLARE
@tmpSql VARCHAR(900),
@dbname VARCHAR(300),
@tablename VARCHAR(300),
@tableid INT,
@indid INT,
@lostIndex INT,
@i INT
CREATE TABLE #tmp_lost_col_index(
dbname VARCHAR(300),
tablename VARCHAR(300)
)
CREATE TABLE #tmp_tbs(
tablename VARCHAR(300),
tableid INT
)
CREATE TABLE #tmp_idx(
indid INT
)
--1.定义游标(所有符合前缀条件的库名)
DECLARE dbs CURSOR FOR SELECT name FROM master..sysdatabases WHERE name LIKE @dbname_prefix + '%'
--2.打开游标
OPEN dbs
--3.获取记录
FETCH dbs INTO @dbname
--4.循环处理每个库
WHILE @@FETCH_STATUS = 0
BEGIN
--4.1 清空临时表
TRUNCATE TABLE #tmp_tbs
--4.2处理临时表
SELECT @tmpSql = 'INSERT INTO #tmp_tbs SELECT name, id FROM ' + @dbname + '..sysobjects WHERE type = ''U'' AND EXISTS (SELECT 1 FROM ' + @dbname + '..syscolumns WHERE name = ''' + @col_name + ''' AND id = ' + @dbname + '..sysobjects.id)'
PRINT @tmpSql
EXECUTE (@tmpSql)
--4.2.1 定义表列表游标
DECLARE tbs CURSOR FOR SELECT tablename, tableid FROM #tmp_tbs
--4.2.2 打开表列表游标
OPEN tbs
--4.2.3 获取记录
FETCH tbs INTO @tablename, @tableid
--4.2.4状态为正常
WHILE @@FETCH_STATUS = 0
BEGIN
--4.2.5处理所有索引
TRUNCATE TABLE #tmp_idx
SELECT @tmpSql = 'INSERT INTO #tmp_idx SELECT indid FROM ' + @dbname + '..sysindexes WHERE id = ' + CONVERT(VARCHAR, @tableid) + ' AND indid > 0 AND indid < 255'
EXECUTE (@tmpSql)
SELECT @lostIndex = -1
--4.2.5.1 循环处理每个索引
DECLARE idxs CURSOR FOR SELECT indid FROM #tmp_idx
OPEN idxs
FETCH idxs INTO @indid
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @i = 1
WHILE @i <= 31
BEGIN
--如果字段相同,则修改状态并跳出循环
IF index_col(@dbname + '..' + @tablename, @indid, @i) = @col_name
BEGIN
SELECT @lostIndex = 1
BREAK
END
SELECT @i = @i + 1
END
--标记大于1时代表对应字段在索引中最低出现了一次,判断下一个表
IF @lostIndex > -1
BEGIN
BREAK
END
FETCH idxs INTO @indid
END
CLOSE idxs
DEALLOCATE idxs
IF @lostIndex < 0
BEGIN
INSERT INTO #tmp_lost_col_index SELECT @dbname, @tablename
END
--4.2.6处理下一条
FETCH tbs INTO @tablename, @tableid
END
CLOSE tbs
DEALLOCATE tbs
--4.3 处理下一条
FETCH dbs INTO @dbname
END
--5.关闭游标
CLOSE dbs
--6.销毁游标
DEALLOCATE dbs
SELECT dbname, tablename FROM #tmp_lost_col_index
DROP TABLE #tmp_idx
DROP TABLE #tmp_tbs
DROP TABLE #tmp_lost_col_index
END
GO
二、执行函数
USE tempdb
GO
EXECUTE tempdb..PR_QUERY_COL_INDEX_LOST 'DB_TASK', 'N_ID'
GO
三、查看结果
执行完毕后返回的结果集就是我们想要的结果。在需要时也可以修改存储过程中的临时表为实体表,根据需求调整即可