南卡罗来纳州 内部联接信息\u schema.tables作为t 关于c.table\u name=t.table\u name 哪里 t、 表\u type='base table'和 t、 table_name=@tablename 设置@sql=left(@sql,len(@sql)-10) --打印@sql exec(@sql) 结束
你可以在这篇博文中找到更多细节挑战: 下面这样的模式更改使我们的填充率方法比实际的方法稍微困难一些南卡罗来纳州 内部联接信息\u schema.tables作为t 关于c.table\u name=t.table\u name 哪里 t、 表\u type='base table'和 t、 table_name=@tablename 设置@sql=left(@sql,len(@sql)-10) --打印@sql exec(@sql) 结束,sql,sql-server,tsql,Sql,Sql Server,Tsql,你可以在这篇博文中找到更多细节挑战: 下面这样的模式更改使我们的填充率方法比实际的方法稍微困难一些 表名更改 列名更改 数据类型更改 删除现有列 添加新列 由于上述挑战,我们不能简单地使用静态解决方案来查找表的填充率。相反,我们需要一些类似动态的方法来避免我们未来的重复工作 先决条件: 在下面的示例中,我们将使用一个名为“Get_FillRate”的存储过程进行演示。如果数据库中有任何对象名称相同,请确保更改以下存储过程名称 使用数据加载脚本创建示例表 临时表-#测试计划 在表动
- 表名更改
- 列名更改
- 数据类型更改
- 删除现有列
- 添加新列
- 创建了名为“Get_FillRate”的存储过程
- 要避免返回的行数,请将NOCOUNT设置为ON
- 尝试,为错误处理添加捕获块
- 要读取未提交的修改,请将事务隔离级别设置为read Uncommitted
- 还包括参数嗅探概念
- 对表名输入参数进行了一些处理,以支持用户键入表名格式,如“.Table_Name”、“Table_Name”、“Table_Name”、“Table_Name”、“Table_Name”、“dbo.Table_Name”、“dbo.[Table_Name]”、“[dbo].[Table_Name]”等
- 验证包括在开始时,当用户给出的不是“表名”时,存储过程将抛出“此数据库中不存在表”作为错误消息
- 存储过程中使用名为SYS.OBJECTS和SYS.COLUMNS的系统表以及名为INFORMATION_SCHEMA.COLUMNS的系统视图
- 使用INFORMATION_SCHEMA.COLUMNS中的ORDINAL_POSITION返回结果集,其列顺序与表结构中已有的列顺序相同
- CudioNo.NealNo.Studio。使用列来支持诸如空白的条件,无论是否需要考虑,如未填写的条目。
- 使用INFORMATION_SCHEMA.COLUMNS中的COLUMN_NAME来显示具有相应填充率的最终结果集
- 使用动态查询来支持动态方法,这将避免静态解决方案(如模式更改)带来的所有挑战
- 方法1(带WHILE循环的动态查询)和方法2(带UNION ALL的动态查询)都会生成相同的结果集,并具有相同的功能,其中一些指标(如CPU时间、运行时间、逻辑读取)在方法2中更好
如果需要将空值和空/空值都考虑为未填充
,则执行如下所示EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;
方法1-输出
方法2-使用UNION ALL
如果需要将空值和空/空值都考虑为未填充
,则执行如下所示EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;
方法2-输出
方法1与方法2之间的度量差异
为了了解方法1和方法2之间的差异,需要考虑以下四个指标
- Exec查询计划中的查询集数
- 总CPU时间(毫秒)
- 总运行时间(毫秒)
- 总逻辑读取数
总之,我们已经了解了如何使用T-SQL查询查找表的填充率,该查询适用于在AZURE和本地SQL数据库中运行。因此,它将有助于我们立即有效地做出业务决策。挑战: 下面这样的模式更改使我们的填充率方法比实际的方法稍微困难一些
- 表名更改
- 列名更改
- 数据类型更改
- 删除现有列
- 添加新列
--dropping temp table if exists
IF OBJECT_ID('TempDb..#TestEmp') IS NOT NULL
DROP TABLE #TestEmp;
CREATE TABLE #TestEmp
(
[TestEmp_Key] INT IDENTITY(1,1) NOT NULL,
[EmpName] VARCHAR(100) NOT NULL,
[Age] INT NULL,
[Address] VARCHAR(100) NULL,
[PhoneNo] VARCHAR(11) NULL,
[Inserted_dte] DATETIME NOT NULL,
[Updated_dte] DATETIME NULL,
CONSTRAINT [PK_TestEmp] PRIMARY KEY CLUSTERED
(
TestEmp_Key ASC
)
);
GO
INSERT INTO #TestEmp
(EmpName,Age,[Address],PhoneNo,Inserted_dte)
VALUES
('Arul',24,'xxxyyy','1234567890',GETDATE()),
('Gokul',22,'zzzyyy',NULL,GETDATE()),
('Krishna',24,'aaa','',GETDATE()),
('Adarsh',25,'bbb','1234567890',GETDATE()),
('Mani',21,'',NULL,GETDATE()),
('Alveena',20,'ddd',NULL,GETDATE()),
('Janani',30,'eee','',GETDATE()),
('Vino',26,NULL,'1234567890',GETDATE()),
('Madhi',25,'ggg',NULL,GETDATE()),
('Ronen',25,'ooo',NULL,GETDATE()),
('Visakh',25,'www',NULL,GETDATE()),
('Jayendran',NULL,NULL,NULL,GETDATE());
GO
SELECT [TestEmp_Key],[EmpName],[Age],[Address],[PhoneNo],[Inserted_dte],[Updated_dte] FROM #TestEmp;
GO
CREATE OR ALTER PROCEDURE [dbo].[Get_FillRate]
(
@p_TableName NVARCHAR(128),
@p_Include_BlankAsNotFilled BIT = 0 -- 0-OFF(Default); 1-ON(Blank As Not Filled Data)
)
AS
BEGIN
BEGIN TRY
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--Parameter Sniffing
DECLARE @TableName NVARCHAR(128),
@Include_BlankAsNotFilled BIT,
@ColumnName NVARCHAR(128),
@R_NO INT,
@DataType_Field BIT,
@i INT, --Iteration
@RESULT NVARCHAR(MAX);
SELECT @TableName = @p_TableName,
@Include_BlankAsNotFilled = @p_Include_BlankAsNotFilled,
@i = 1;
--To Support some of the table formats that user typing.
SELECT @TableName =REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@TableName,'[',''),']',''),'dbo.',''),'...',''),'..',''),'.','');
--validation
IF NOT EXISTS(SELECT 1 FROM SYS.OBJECTS WHERE [TYPE]='U' AND [NAME]=@TableName )
BEGIN
SELECT Result = 1 , Reason ='Table not exists in this Database' ;
RETURN 1;
END;
--dropping temp table if exists - for debugging purpose
IF OBJECT_ID('TempDb..#Temp') IS NOT NULL
DROP TABLE #Temp;
IF OBJECT_ID('TempDb..#Columns') IS NOT NULL
DROP TABLE #Columns;
--temp table creations
CREATE TABLE #Temp
(
[R_NO] INT NOT NULL,
[ColumnName] NVARCHAR(128) NOT NULL,
[FillRate] DECIMAL(5,2) NOT NULL
PRIMARY KEY CLUSTERED (ColumnName)
);
CREATE TABLE #Columns
(
[R_NO] INT NOT NULL,
[Name] [sysname] NOT NULL,
[DataType_Field] BIT NOT NULL
PRIMARY KEY CLUSTERED ([Name])
);
INSERT INTO #Columns ([R_NO],[Name],[DataType_Field])
SELECT
COLUMN_ID,
[Name],
IIF(collation_name IS NULL,0,1)
FROM SYS.COLUMNS WHERE OBJECT_ID = OBJECT_ID(@TableName);
WHILE @i <= ( SELECT MAX(R_NO) FROM #Columns) --Checking of Iteration till total number of columns
BEGIN
SELECT @DataType_Field=DataType_Field,@ColumnName=[Name],@R_NO=[R_NO] FROM #Columns WHERE R_NO = @i;
SET @RESULT =
'INSERT INTO #Temp ([R_NO],[ColumnName], [FillRate]) ' +
'SELECT ' + QUOTENAME(@R_NO,CHAR(39)) + ',
''' + @ColumnName + ''',
CAST((100*(SUM(
CASE WHEN ' +
CASE
WHEN @Include_BlankAsNotFilled = 0
THEN '[' + @ColumnName + '] IS NOT NULL'
WHEN @DataType_Field = 0
THEN '[' + @ColumnName + '] IS NOT NULL'
ELSE 'ISNULL([' + @ColumnName + '],'''')<>'''' ' END +
' THEN 1 ELSE 0 END)*1.0 / COUNT(*)))
AS DECIMAL(5,2))
FROM ' + @TableName;
--PRINT(@RESULT); --for debug purpose
EXEC(@RESULT);
SET @i += 1; -- Incrementing Iteration Count
END;
--Final Result Set
SELECT
ColumnName AS [Column Name],
FillRate AS [Fill Rate (%)]
FROM #TEMP
ORDER BY [R_NO];
RETURN 0;
END TRY
BEGIN CATCH --error handling even it is fetching stored procedure
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
RETURN 1;
END CATCH;
END;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;
CREATE OR ALTER PROCEDURE [dbo].[Get_FillRate]
(
@p_TableName NVARCHAR(128),
@p_Include_BlankAsNotFilled BIT = 0 -- 0-OFF(Default); 1-ON(Blank As Not Filled Data)
)
AS
BEGIN
BEGIN TRY
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--Parameter Sniffing
DECLARE @TableName NVARCHAR(128),
@Include_BlankAsNotFilled BIT,
@RESULT NVARCHAR(MAX);
SELECT @TableName = @p_TableName,
@Include_BlankAsNotFilled = @p_Include_BlankAsNotFilled,
@RESULT = '';
--To Support some of the table formats that user typing.
SELECT @TableName =REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@TableName,'[',''),']',''),'dbo.',''),'...',''),'..',''),'.','');
--validation
IF NOT EXISTS(SELECT 1 FROM SYS.OBJECTS WHERE [TYPE]='U' AND [NAME]=@TableName )
BEGIN
SELECT Result = 1 , Reason ='Table not exists in this Database' ;
RETURN 1;
END;
--dropping temp table if exists - for debugging purpose
IF OBJECT_ID('TempDb..#Columns') IS NOT NULL
DROP TABLE #Columns;
--temp table creations
CREATE TABLE #Columns
(
[ORDINAL_POSITION] INT NOT NULL,
[COLUMN_NAME] [sysname] NOT NULL,
[DataType_Field] BIT NOT NULL,
[TABLE_NAME] [sysname] NOT NULL
PRIMARY KEY CLUSTERED ([ORDINAL_POSITION],[COLUMN_NAME])
);
INSERT INTO #Columns ([ORDINAL_POSITION],[COLUMN_NAME],[DataType_Field],[TABLE_NAME])
SELECT
[ORDINAL_POSITION],
[COLUMN_NAME],
CASE WHEN COLLATION_NAME IS NOT NULL THEN 1 ELSE 0 END,
[TABLE_NAME]
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =@tablename; --Using System_View
--Final Result Set
SELECT @RESULT = @RESULT+ N'SELECT '''+C.COLUMN_NAME+''' AS [Column Name],
CAST((100*(SUM(
CASE WHEN ' +
CASE
WHEN @include_blankasnotfilled = 0
THEN '[' + C.COLUMN_NAME + '] IS NOT NULL'
WHEN C.[DataType_Field]=0
THEN '[' + C.COLUMN_NAME + '] IS NOT NULL'
ELSE 'ISNULL([' + C.COLUMN_NAME + '],'''')<>'''' ' END +
' THEN 1 ELSE 0 END)*1.0 / COUNT(*)))
AS DECIMAL(5,2)) AS [Fill Rate (%)]
FROM '+C.TABLE_NAME+' UNION ALL '
FROM #Columns C;
SET @RESULT=LEFT(@RESULT,LEN(@RESULT)-10); --To Omit 'Last UNION ALL '.
--PRINT(@RESULT); --for debug purpose
EXEC(@RESULT);
RETURN 0;
END TRY
BEGIN CATCH --error handling even it is fetching stored procedure
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
RETURN 1;
END CATCH;
END;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=0;
EXEC [Get_FillRate] @p_TableName='#TestEmp',@p_Include_BlankAsNotFilled=1;