• SQL Server中修改“用户自定义表类型”问题的分析与方法


    前言:

    SQL Server开发过程中,为了传入数据集类型的变量(比如接受C#中的DataTable类型变量),需要定义“用户自定义表类型”,通过“用户自定义表类型”可以接收二维数据集作为参数,在需要修改“用户自定义表类型”的时候,增加字段,删除字段,修改字段类型等,它没有像表一样的alter table语法来进行修改。

    用户自定义表类型

    “用户自定义表类型”只能通过删除重建来实现,但是在删除的时候会提示有对象引用它(某些存储过程用到了这个“用户自定义表类型”),因此无法删除。

    为了达到公用的目的,有时候一个TableType可以在多个地方分别被引用到,这样的话,势必要先删除所有的引用了这个“用户自定义表类型”的对象(存储过程等)

    如果这个“用户自定义表类型”被多个存储过程引用,那么就要分别删除多个引用了“用户自定义表类型”的存储过程,然后修改“用户自定义表类型”,在重建存储过程,这样做起来似乎有点绕,这个问题可以用过EXEC sys.sp_refreshsqlmodule这个系统函数来简介实现“用户自定义表类型”的定义

    一、TableType的基本使用

    如下创建一个用户自定义表类型

    定义的TableType可以在用户自定义表类型中找到

    创建两个存储过程,分别用到了上面定义的用户自定义表类型,模拟用户自定义表类型被引用的情况

    此时的存储过程可以接收TableType参数并正常运行

    1.1 脚本如下

     1 -- 创建一个用户自定义表类型
     2 CREATE TYPE MyTableType AS TABLE(
     3     Id INT NOT NULL,
     4     Name VARCHAR(255) NOT NULL
     5 )
     6 
     7 GO
     8 
     9 --创建两个存储过程,分别用到了上面定义的用户自定义表类型,模拟用户自定义表类型被引用的情况
    10 CREATE PROC test_proc1(
    11     @tb MyTableType READONLY
    12 )
    13 AS
    14 BEGIN
    15     SELECT * FROM @tb
    16 END
    17 GO
    18 
    19 
    20 CREATE PROC test_proc2(
    21     @tb MyTableType READONLY
    22 )
    23 AS
    24 BEGIN
    25     SELECT * FROM @tb
    26 END
    27 GO
    28 
    29 -- 此时的存储过程可以接收TableType参数并正常运行
    30 DECLARE @tb MyTableType
    31 INSERT INTO @tb(Id,Name) VALUES(1,'aa'),(2,'bb')
    32 EXEC test_proc1 @tb
    33 GO

    二、TableType的修改

    TableType类型不支持alter语法,也即无法直接修改TableType的定义

    那么只能通过删除TableType的方法来重建这个TableType,当删除的时候,仍然报错,提示“因为它正由对象 '***' 引用。可能还有其他对象在引用此类型。”

    此时只能删除引用了这个TableType的对象来解决,下面可以查到那些对象引用了某一个TableType,然后分别删除,重建TableType,再重建存储过程,有点绕弯子。

    可以先将自定义的某个TableType重命名,重命名的过程中有一个警告,这里先忽略它,随后可以直接Drop Type dbo.MyTableType

    删除原TableType之后,重建(重定义)TableType

    重建TableType之后,先前存储过程中用到这个TableType的存储过程是无法编译通过的

    此时就需要重新刷新引用对象的定义

    刷新完成之后,原存储过程就可以正常编译了

    最后删除原始的TableType被重命名的TableType(被第一步重名的那个)

    这样子,整个过程就无需因为修改TableType的定义而删除引用了TableType的对象了,在修改了TableType的定义之后,引用了这个TableType的对象可以正常运行,也可以根据修改之后的TableType做具体的使用

    2.1 完整的脚本如下

     1 --判断Type是否存在,如果存在,重命名,随后之后才再删除,否则无法直接删除
     2 IF EXISTS (SELECT 1 FROM sys.types t join sys.schemas s on t.schema_id=s.schema_id 
     3       and t.name='MyTableType' and s.name='dbo')
     4  EXEC sys.sp_rename 'dbo.MyTableType', 'obsoleting_MyTableType';
     5 GO
     6  
     7  
     8 --重建TYPE,比如原来是四个字段,现在想修改为三个字段,或者原来有三个字段想加一个字段变成四个字段
     9 CREATE TYPE dbo.MyTableType AS TABLE(
    10  Id INT NOT NULL,
    11  Name VARCHAR(255) NOT NULL,   Remark VARCHAR(255)
    12 )
    13 GO
    14  
    15 --将原来引用将要删除的TYPE全部重建一遍,否则原始存储过程会报错
    16 DECLARE @Name NVARCHAR(500);
    17 DECLARE REF_CURSOR CURSOR FOR
    18 SELECT referencing_schema_name + '.' + referencing_entity_name
    19 FROM sys.dm_sql_referencing_entities('dbo.MyTableType', 'TYPE');
    20  OPEN REF_CURSOR;
    21  FETCH NEXT FROM REF_CURSOR INTO @Name;
    22  WHILE (@@FETCH_STATUS = 0)
    23  BEGIN
    24   EXEC sys.sp_refreshsqlmodule @name = @Name;
    25   FETCH NEXT FROM REF_CURSOR INTO @Name;
    26  END;
    27 CLOSE REF_CURSOR;
    28 DEALLOCATE REF_CURSOR;
    29 GO
    30  
    31 --最后删除原始的被重命名的TableType(被第一步重名的那个)
    32 IF EXISTS (SELECT 1 FROM sys.types t 
    33    join sys.schemas s on t.schema_id=s.schema_id 
    34    and t.name='obsoleting_MyTableType' and s.name='dbo')
    35  DROP TYPE dbo.obsoleting_MyTableType
    36 GO
    37  
    38 --最后执行授权
    39 GRANT EXECUTE ON TYPE::dbo.MyTableType TO public
    40 GO

    三、总结:

    TableType可以方便地接受二维数据作为参数,从而可以达到批量处理数据的目的,避免传递进去一大堆字符串,然后在对字符串解析的做法,从而可以在一定程度上提高sql的运行效率。

    不过TableType的修改确实存在一定的问题,直接修改TableType会存在级联删除数据库对象的情况,可以通过“曲线救国”的方式,来减小工作量的情况下修改TableType。

    作者:JamelAr
    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    增强for循环赋值并且向list集合里添加元素,每个元素都一样
    《《《Spring 视频学习笔记
    xml中的<where><if>模糊查询
    《《《layui入门笔记
    《《《Vue element学习笔记
    《《《Spring Boot视频学习笔记
    intellij idea设置打开多个文件显示在多行tab上
    postMan安装完成,打开提示找不到,或者报错 可能原因
    Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录
    idea代码注释
  • 原文地址:https://www.cnblogs.com/JamelAr/p/14986922.html
Copyright © 2020-2023  润新知