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

前言

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

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

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

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

TableType的基本使用

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

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

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

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

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做具体的使用

完整的脚本如下

--判断Type是否存在,如果存在,重命名,随后之后才再删除,否则无法直接删除 IF EXISTS (SELECT 1 FROM sys.types t join sys.schemas s on t.schema_id=s.schema_id and t.name='MyTableType' and s.name='dbo') EXEC sys.sp_rename 'dbo.MyTableType', 'obsoleting_MyTableType'; GO --重建TYPE,比如原来是四个字段,现在想修改为三个字段,或者原来有三个字段想加一个字段变成四个字段 CREATE TYPE dbo.MyTableType AS TABLE( Id INT NOT NULL, Name VARCHAR(255) NOT NULL,   Remark VARCHAR(255) ) GO --将原来引用将要删除的TYPE全部重建一遍,否则原始存储过程会报错 DECLARE @Name NVARCHAR(500); DECLARE REF_CURSOR CURSOR FOR SELECT referencing_schema_name + '.' + referencing_entity_name FROM sys.dm_sql_referencing_entities('dbo.MyTableType', 'TYPE'); OPEN REF_CURSOR; FETCH NEXT FROM REF_CURSOR INTO @Name; WHILE (@@FETCH_STATUS = 0) BEGIN EXEC sys.sp_refreshsqlmodule @name = @Name; FETCH NEXT FROM REF_CURSOR INTO @Name; END; CLOSE REF_CURSOR; DEALLOCATE REF_CURSOR; GO --最后删除原始的被重命名的TableType(被第一步重名的那个) IF EXISTS (SELECT 1 FROM sys.types t join sys.schemas s on t.schema_id=s.schema_id and t.name='obsoleting_MyTableType' and s.name='dbo') DROP TYPE dbo.obsoleting_MyTableType GO --最后执行授权 GRANT EXECUTE ON TYPE::dbo.MyTableType TO public GO

总结:

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

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

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

时间: 2024-09-21 05:32:12

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

在SQL Server中修改字段类型和字段名称

  在SQL Server中修改字段类型和字段名称 --以下是完整的SQL执行语句 if exists(select * from syscolumns where id=object_id('数据表名称') and name='字段名') --判断该字段是否存在 begin ALTER TABLE 表明 ALTER COLUMN 字段名 VARCHAR(64);--更改类型 end GO if exists(select * from syscolumns where id=object_id

在 SQL Server 中查询EXCEL 表中的数据遇到的各种问题

原文:在 SQL Server 中查询EXCEL 表中的数据遇到的各种问题 SELECT * FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0','Data Source="D:\KK.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...[Sheet1$] 问题:消息 15281,级别 16,状态 1,第 1 行 SQL Server 阻止了对组件 'Ad Hoc Dis

SQL Server中统计每个表行数的快速方法

这篇文章主要介绍了SQL Server中统计每个表行数的快速方法,本文不使用传统的count()函数,因为它比较慢和占用资源,本文讲解的是另一种方法,需要的朋友可以参考下 我们都知道用聚合函数count()可以统计表的行数.如果需要统计数据库每个表各自的行数(DBA可能有这种需求),用count()函数就必须为每个表生成一个动态SQL语句并执行,才能得到结果.以前在互联网上看到有一种很好的解决方法,忘记出处了,写下来分享一下. 该方法利用了sysindexes 系统表提供的rows字段.rows

Sql Server中操作表及表结构的Select合集

1.增加字段 alter table docdsp     add dspcode char(200) 2.删除字段 ALTER TABLE table_NAME DROP COLUMN column_NAME 3.修改字段类型 ALTER TABLE table_name     ALTER COLUMN column_name new_data_type 4.sp_rename 改名 EXEC sp_rename '[dbo].[Table_1].[filedName1]', 'filedN

SQL Server中合并用户日志表的方法

server 在维护SQL Server数据库的过程中,大家是不是经常会遇到成千上万的类似log20050901 这种日志表,每一个表中数据都不是很多,一个一个打开看非常不方便,或者有时候我们需要把这些表中的资料汇总,一个一个打开操作也是很麻烦.下面就介绍了一种自动化的合并表的方法. 我的思路是创建一个用户存储过程来完成一系列自动化的操作,以下是代码. --存储过程我命名为BackupData,可以使用自己定义的名称. --参数1:@TableTarget 生成的目标表的名称 --参数2:@Ta

SQL Server中临时表与表变量有什么区别

我们在数据库中使用表的时候,经常会遇到两种使用表的方法,分别就是使用临时表及表变量.在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQLServer的系统日志,虽它们在Tempdb中体现,是分配

SQL Server中聚合历史备份信息对比数据库增长的方法_MsSql

很多时候,在我们规划SQL Server数据库的空间,或向存储方面要空间时,都需要估算所需申请数据库空间的大小,估计未来最简单的办法就是看过去的趋势,这通常也是最合理的方式. 通常来讲,一个运维良好的数据库都需要做定期基线(baseline),有了基线才会知道什么是正常.一个简单的例子例如,一些人的血压平常偏低,那么80的低压对他来说就是不正常了.但现实情况是大多数系统并没有采集基线的习惯,因此在需要规划空间想要看历史增长时,就没有过去精确的数据了. 一个解决办法就是通过查看历史备份的大小来看过

SQL Server中聚合历史备份信息对比数据库增长的方法

很多时候,在我们规划SQL Server数据库的空间,或向存储方面要空间时,都需要估算所需申请数据库空间的大小,估计未来最简单的办法就是看过去的趋势,这通常也是最合理的方式. 通常来讲,一个运维良好的数据库都需要做定期基线(baseline),有了基线才会知道什么是正常.一个简单的例子例如,一些人的血压平常偏低,那么80的低压对他来说就是不正常了.但现实情况是大多数系统并没有采集基线的习惯,因此在需要规划空间想要看历史增长时,就没有过去精确的数据了. 一个解决办法就是通过查看历史备份的大小来看过

SQL Server中临时表与表变量的区别

  我们在数据库中使用表的时候,经常会遇到两种使用表的方法,分别就是使用临时表及表变量.在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQLServer的系统日志,虽它们在Tempdb中体现,是