sql server查询可编程对象定义的方式对比以及整合

Posted 剑走江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql server查询可编程对象定义的方式对比以及整合相关的知识,希望对你有一定的参考价值。

1、sql server查看可编程对象定义的方式对比
 
上一篇博文重构sql server的sys.helptext存储中写了sys.helptext的限制和输出格式每行自带char(13)和char(10)这两个字符。为了将可编程对象定义查询方式研究透彻,以下表格列出了查询可编程对象定义的不同方式的却别和对可编程对象定义查看的支持程度。
对象类型描述 对象类型简写
sys.sp_helptext
sys.sql_modules
sys.system_sql_modules
sys.all_sql_modules
object_definition
CHECK_CONSTRAINT
C
支持 不支持
不支持
不支持
支持
DEFAULT_CONSTRAINT(contraint,stand-alone)
D
支持 支持
不支持
支持
支持
SQL_SCALAR_FUNCTION
FN
支持
支持
支持
支持
支持
SQL_INLINE_TABLE_VALUED_FUNCTION
IF
支持
支持
支持
支持
支持
SQL_STORED_PROCEDURE
P
支持
支持 支持
支持
支持
RULE(old-style,stand-alone)
R
支持
支持
不支持
支持
支持
REPLICATION FILTER PROCEDURE
RF
支持
支持
支持
支持
支持
SQL_TABLE_VALUED_FUNCTION
TF
支持
支持
支持
支持
支持
SQL_TRIGGER
TR
支持(除数据库DDL触发器和服务器触发器外)
支持(除服务器触发器外)
不支持
支持(除服务器触发器外)
支持(除服务器触发器外)
USER_TABLE
U
computed_column
支持
不支持
不支持
不支持
不支持
VIEW
V
支持
支持
支持
支持
支持

注意:

1、带有_modules的是系统提供的目录视图类。
2、sys.sql_modules包括所有用户定义的可编程对象的,当然也不支持计算列和服务器触发器的。
3、sys.system_sql_modules不支持系统定义的类型为C、D、R、TR的对象。
4、sys.all_sql_modules就是sys.sql_modules和sys.system_sql_modules这个视图的并集结果的,当然也不支持系统定义的类型为C、D、R、TR类型的对象。
5、sys.sp_helptext虽然支持以上表格中除数据库DDL触发器和服务器触发器之外的可编程对象,但是其输出格式有限制:1、每行最多225双字节字符号,这样有可能造成输出将一个标识符分割为前后两行的。
6、object_definition函数支持以上表格中除服务器除触发器和计算列外的可以变成对象。
7、sys.sp_helpttext和object_definition有个功能的限制:1、在SSMS客户端中如果使用字符串类型变量接收返回的而结果,有可能受制于SSMS客户端针对字符串变量的最大限制(sql server 2012中的最大限制是43679双字节字符长度)不能全部输出到客户端,这个缺点可以从通过程序编码实现得到完美体现。
 
2、整合实现所有可编程对象定义的查看功能的存储dbo.usp_helptext2
 
通过以上几种方式的对比,我们可以看到那个方式都不能将以上表格中列出的对象类型的定义全部都满足,为了解决这个不足,我们将整合这些功能来封装在一个存储(其名称为dbo.usp_helptext2)。需要注意的一点就是服务器触发器本来不是某个数据库中的对象的,服务器触发器和数据库中可编程对象分开更好的理解,也能简单些的,不过为了查询的便利性,我们这次封装的存储实现服务器触发器定义查看。
 
功能整合的存储过程T-SQL代码如下:
IF OBJECT_ID(N\'[dbo].[usp_helptext2]\', \'P\') IS NOT NULL
BEGIN
    DROP PROCEDURE [dbo].[usp_helptext2];
END
GO
 
--==================================
-- 功能: 查看可编程对象定义
-- 说明: 支持用户定义类型,可以运行于SQL Server 2005+
-- 创建: yyyy-MM-dd hh:mm-hh:mm XXX 创建内容描述
-- 修改: yyyy-MM-dd hh:mm-hh:mm XXX 修改内容描述
--==================================
CREATE PROCEDURE [dbo].[usp_helptext2]
(
     @nvcObjectName AS NVARCHAR(776)                    -- 对象名称,可以支持的对象类型为(C、D、FN、IF、P、R、RF、TF、TR、U、V)
    ,@nvcComputedColumnName AS NVARCHAR(128) = NULL        -- 计算列名称(如果@nvcObjectName的对象类型为U,则该参数表示计算列名称)
)
AS
BEGIN
    SET NOCOUNT ON;
 
    SET @nvcObjectName = ISNULL(@nvcObjectName, N\'\');
    IF (@nvcObjectName = N\'\')
    BEGIN
        RAISERROR(16902, -1, -1,N\'usp_helptext2\', N\'@nvcObjectName\');
        RETURN(1);
    END
 
    SET @nvcComputedColumnName = ISNULL(@nvcComputedColumnName, N\'\');
 
    DECLARE @tntRetVal AS TINYINT;
    SET @tntRetVal = 0;
 
    DECLARE @tblObjDef AS TABLE (
        [Text] NVARCHAR(1000) NULL
    );
 
    DECLARE
         @intObjectID AS INT
        ,@chaType AS CHAR(2)
        ,@nvcText AS NVARCHAR(MAX);
    SELECT
         @intObjectID = 0
        ,@chaType = \'\'
        ,@nvcText = N\'\';
    SELECT
         @intObjectID = [object_id]
        ,@chaType = [type]        
    FROM [sys].[all_objects]
    WHERE 
        [type] IN (\'C\', \'D\', \'FN\', \'IF\', \'P\', \'R\', \'RF\', \'TF\', \'TR\', \'U\', \'V\')
        AND [name] = PARSENAME(@nvcObjectName, 1);
 
    IF (@nvcComputedColumnName > N\'\')    -- 获取计算列定义
    BEGIN
        IF (@chaType NOT IN (\'S\', \'U\', \'TF\'))
        BEGIN
            RAISERROR(15218, -1, -1, @nvcObjectName);
            RETURN(1);
        END
 
        INSERT INTO @tblObjDef ([Text])        
        EXEC [sys].[sp_helptext]
             @objname = @nvcObjectName                -- nvarchar(776)
            ,@columnname = @nvcComputedColumnName    -- sysname
 
        IF(@@ROWCOUNT = 0)
        BEGIN
            SET @tntRetVal = 1;
        END
 
        SELECT 
            @nvcText = ISNULL([Text], N\'\')
        FROM @tblObjDef;            
    END
    ELSE IF (@intObjectID <> 0)    -- 获取除计算列和服务器触发器以外的所有对象类型的定义
    BEGIN
        SET @nvcText = OBJECT_DEFINITION(@intObjectID);
 
        IF(@@ROWCOUNT = 0)
        BEGIN
            SET @tntRetVal = 1;
        END
    END
    ELSE IF (@intObjectID = 0)    -- 尝试获取服务器触发器定义
    BEGIN
        SELECT 
            @nvcText = T1.[definition]
        FROM [sys].[server_sql_modules] AS T1
            INNER JOIN [sys].[server_triggers] AS T2
                ON [T1].[object_id] = [T2].[object_id]
        WHERE T2.[name] = @nvcObjectName;
 
        IF(@@ROWCOUNT = 0)
        BEGIN
            SET @tntRetVal = 1;
        END
    END
 
    SELECT 
        @nvcText AS [Text];
 
    RETURN(@tntRetVal);
END
GO
 

 

以上存储dbo.usp_helptext2可以完全实现以上表格的所有可编程对象定义查看,不论是系统定义的还是用户定义的,前提是以上表格中的可编程对象类型定义。当然也存在缺点就是可编程对象定义输出到SSMS客户端超过最大限制(SQL Server 2012环境中的时43679双字节字符长度)就要出现截断,这个缺点可以通过代码编程来完美解决这个缺点。
 
3、dbo.helptext2的选择性测试
 
用户定义检查约束测试:
用户定义约束测试:
系统定义存储测试:
用户定义计算列测试:
 
数据库DDL触发器测试
服务器触发器测试:
其他对象类型的测试不在全部列举。
 
4、总结语
 
在这次的学习和研究,sql server系统自带的视图以及存储过程针对可编程对象的实现很很完善的,不过叶分散在不同的地方,这次整合也就是将分散在不同地方的聚合在一起提供统一入口来处理。如果不想查看计算列和服务器触发器的定义以外的所有可编程对象类型的定义,建议使用object_definition函数,该函数几乎提供了很完善的功能。这次学习也发现数据库DDL触发器在sys.object是无法查看到的,需要在sys.triggers或sys.all_objects目录视图中查看到,这个也在object_id函数做了限制的。由于服务器触发器本身属于服务器的,这个sql server团队本身也是用了系统表sys.sysschobjs、sys.syspalnames 、sys.syspalvalues,虽然sys.all_objects也是用了系统表sys.syscheobjs,但是却在sys.all_objects中无法查询到的,也在object_id函数中做了限制,只能在sys.server_triggers查询到,这从逻辑上进行了分离,也符合服务器触发器的归属性质。
 
希望这个整合的查看可编程对象定义的存储,可以帮助到需要的人。继续精进,继续探究sql server。
 
5、参考清单列表

以上是关于sql server查询可编程对象定义的方式对比以及整合的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式创建新的本地 SQL Server 实例?

以编程方式创建 SQL Server 代理作业

SQL Server,Oracle,DB2索引建立语句的对比

如何在.NET中以编程方式在SQL Server中获取VIEW的sql代码

SQL Server 2005 - 以编程方式导出表(运行 .sql 文件来重建它)

在sql server中以编程方式将内置帐户更改为本地系统