当需要整理一个数据库帮助文档是,可能需要列出库中每个表的列及其属性。这可能在开发一些接口或者外包给别的公司时有帮助。如果需要别人打开SQL Server Management Studio (SSMS)来一个一个查看,无疑是一种折磨。
解决这个问题可以考虑使用系统的目录视图:sys.tables、sys.all_columns、sys.types
提供数据库中每个表对应的一行数据。包括用户表和系统表。而其中的is_ms_shipped列,代表是否为系统表。这在你需要仅仅显式用户表的时候很有用。而不需要在sys.sysobject兼容性视图中通过type=’U’来筛选。
数据库每一个对象的每一列都会返回一行,很多列和sys.type是相同的。但是有些列只能在sys.type中查找。
此目录视图存储系统或者用户自定义数据类型及它们的属性。本文中所需的是数据类型的名字,这列在sys.all_columns中是没有的。同时数据库的排序规则会影响sys.types,所以对于系统内置类型如text,ntext,vachar(),char(),nvarchar(),nchar()会因为数据库不同而不同。
如非必须,最好只查询当前数据库的内容而不要跨数据库,因为这些视图是基于单个数据库的。运行以下语句:
USE AdventureWorks GO SELECT OBJECT_SCHEMA_NAME(T.[object_id], DB_ID()) AS [架构名] , T.[name] AS [表名] , AC.[name] AS [列名] , TY.[name] AS [系统数据类型] , TY.is_user_defined AS [是否用户自定义类型],--1 = 用户定义类型,0 = SQL Server 系统数据类型 AC.[max_length] [最大长度], AC.[precision] [精确度],--如果列包含的是数值,则为该列的精度;否则为0 AC.[scale] [数值范围],--如果列包含的是数值,则为列的小数位数;否则为0 AC.[is_nullable] [是否允许为空], AC.[is_ansi_padded][是否使用ANSI_PADDING]--1 = 如果列为字符、二进制或变量类型,则该列使用ANSI_PADDING ON 行为 FROM sys.[tables] AS T INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] INNER JOIN sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id] AND AC.[user_type_id] = TY.[user_type_id] WHERE T.[is_ms_shipped] = 0 ORDER BY T.[name] , AC.[column_id]
可以得到:
由于某些原因需要在别的库上查询另外一个库的信息时,需要硬编码,如下,可以得到相同的结果:
USE [master] GO SELECT OBJECT_SCHEMA_NAME(T.[object_id], DB_ID('AdventureWorks')) AS [架构名] , T.[name] AS [表名] , AC.[name] AS [列名] , TY.[name] AS [系统数据类型] , TY.is_user_defined AS [是否用户自定义类型],--1 = 用户定义类型,0 = SQL Server 系统数据类型 AC.[max_length] [最大长度], AC.[precision] [精确度],--如果列包含的是数值,则为该列的精度;否则为0 AC.[scale] [数值范围],--如果列包含的是数值,则为列的小数位数;否则为0 AC.[is_nullable] [是否允许为空], AC.[is_ansi_padded][是否使用ANSI_PADDING]--1 = 如果列为字符、二进制或变量类型,则该列使用ANSI_PADDING ON 行为 FROM AdventureWorks.sys.[tables] AS T INNER JOIN AdventureWorks.sys.[all_columns] AC ON T.[object_id] = AC.[object_id] INNER JOIN AdventureWorks.sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id] AND AC.[user_type_id] = TY.[user_type_id] WHERE T.[is_ms_shipped] = 0 ORDER BY T.[name] , AC.[column_id]
最后,通过这些查询结果,可以把数据导出到excel里面供使用。
很多人应该都用过存储过程和触发器,而触发器并不是一个新的概念,它只是一个特殊一些的存储过程, 它可以根据执行的TQL 语句自动执行,不需要我们去调用。
触发器是为了数据库表结构的完成性、一致性而使用的,和单个表的约束一样,触发器是对于表之间的约束,它比主键约束范围更广泛一些,作用范围更大一些,下面给大家介绍一下常用的三种触发器.
【插入触发器(Insert Trigger)】
当向表里面插入记录时候触发
通过临时表(Inserted)来实现,我们需要往表里插入一条记录时,插入的记录先插入到临时表中,然后,从临时表插入到目标表中,为什么采用临时表,我觉的是因为触发器是自动触发,既然是自动触发就不会往里面传参数,那么参数怎么传入到目标表中呢,为了传入参数加入了临时表,将要插入或者删除的记录先放到了临时表中,再从临时表插入数据。
下面是一个校区的基本表TB_Campus,向表里插入数据时触发该触发器,自动向该小区下的建筑表TB_Building添加数据记录,从而保证这两个表的数据一致性。
触发器通常是为了两个表或多个表中数据一致加入的。
例如:
-- ============================================= -- Author: 评教小组-李龙生 -- Create date: 2012年12月29日15:02:06 -- Description: 添加校区记录触发器 -- ============================================= CREATE TRIGGER [dbo].[TR_Campus_Add] on [dbo].[TB_Campus] INSTEAD OF INSERT AS DECLARE @BuildingID VARCHAR(50), --建筑物ID @BuildingName VARCHAR(50), --建筑名 @BuildingCode VARCHAR(50), --建筑代码 @Descriptions VARCHAR(500), --建筑描述 @Operator VARCHAR(50) --操作人 BEGIN --获取要插入记录的标记号(建筑) SELECT @BuildingID=BuildingID from inserted --插入临时表 --插入基本表中的信息(建筑表) INSERT INTO TB_Building(BuildingID,BuildingCode,BuildingName,Descriptions,Operator) VALUES(@BuildingID,@BuildingCode,@BuildingName,@Descriptions,@Operator) END
【更新触发器(Update Trigger)】
当更新表中的任意一个字段时触发
更新触发器需要用到两个表,一个是Inserted 表,另一个是Deleted表,Inserted表存储更新后的记录,Deleted表存储更新后的记录,更新一个表示需要先将要删除的记录放入Deleted表中,然后,将Inserted表的新记录插入表中,从而实现更新操作。
例如:下面是教务系统中一个触发器,更新老师课程关系表(TR_TeachCourseLink)记录,并更新与这个表有关的表。
在更新、删除触发器中我们需要注意一个问题,触发器为什么会触发呢,它是基于SQL 语句而执行的,但更新、删除语句可以一次性删除多条记录,其实SQL 语句只执行了一次,即触发器也只执行一次,那么当涉及到表关系为一对多或者多对多时,就会出现更新或删除不完下面表中记录
为了解决这一问题,我们在下面存储过程中加入了游标,使得更新或删除记录时一条一条的删除,每删除一条,触发器就会执行一次,使得数据保持一致,不过,这样可能大大降低了SQL语句执行速度,如果数据量很大,速度会变慢。
USE [BasicDataSystem] GO /****** Object: Trigger [dbo].[TR_TeachCourseLink_US] Script Date: 2013/1/2 19:28:42 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: 评教小组-李龙生 -- Create date: 2012年12月30日21:03:26 -- Description: 假删除授课表中课表记录 -- 授课课程与虚拟班关系、虚拟班 -- 授课课程与上课班学生关系、上课班学生 -- 课程与选修课学生关系、选修课学生 -- ============================================= ALTER TRIGGER [dbo].[TR_TeachCourseLink_US] ON [dbo].[TBR_TeachCourseLink] AFTER Update AS DECLARE @err1 INT, --存储错误号 @err2 INT, @err3 INT, @err4 INT, @err5 INT, @err6 INT, @err7 INT, @Indexing INT, --授课课程主键 @TeachClassID VARCHAR(36), --虚拟班主键 @StudentID VARCHAR(36) --学生主键 BEGIN --选择要删除授课课程记录的主键 SELECT @Indexing=Indexing FROM deleted --删除临时表 --开启事务 BEGIN TRANSACTION /*更新授课课程记录、授课课程与虚拟班关系、虚拟班,各表中的IsAvailable 字段为 “否”*/ --更新授课课程记录 IsAvailable='否' UPDATE TBR_TeachCourseLink SET IsAvailable='否' WHERE Indexing=@Indexing SET @err1=@@ERROR --更新虚拟班与TeachCourse表的关系 IsAvailable='否' UPDATE TBR_CourseTeachClassLink SET IsAvailable='否' WHERE Indexing=@Indexing SET @err2=@@ERROR --更新虚拟班表 IsAvailable='否'(需要触发多条记录,用游标操作) --声明游标 DECLARE TeachClassCursor CURSOR FOR SELECT TeachClassID FROM TBR_CourseTeachClassLink WHERE Indexing=@Indexing --打开游标 OPEN TeachClassCursor FETCH NEXT FROM TeachClassCursor INTO @TeachClassID --给变量赋初始值 WHILE @@FETCH_STATUS=0 --语句执行成功 BEGIN --更新中的记录 Update TB_TeachClass SET isAvailable = '否' WHERE TeachClassID=@TeachClassID FETCH NEXT FROM TeachClassCursor INTO @TeachClassID END --关闭并释放游标 CLOSE TeachClassCursor DEALLOCATE TeachClassCursor SET @err3=@@ERROR /*更新授课课程与选修课学生关系、学生表,各表中的IsAvailable 字段为 “否”*/ --更新授课课程与选修课学生的关系表IsAvailable='否' UPDATE TBR_StuChooseCourseLink SET IsAvailable='否' WHERE Indexing=@Indexing SET @err6=@@ERROR --更新学生表,将IsAvailable字段变为'否'(需要触发多条记录,用游标操作) --声明游标 DECLARE StudentCursor CURSOR FOR SELECT StudentID FROM TBR_StuChooseCourseLink WHERE Indexing=@Indexing --打开游标 OPEN StudentCursor FETCH NEXT FROM StudentCursor INTO @StudentID --给变量赋初始值 WHILE @@FETCH_STATUS=0 --语句执行成功 begin --更新中的记录 Update TB_Student SET isAvailable = '否' WHERE StudentID=@StudentID FETCH NEXT FROM StudentCursor INTO @StudentID end --关闭并释放游标 CLOSE StudentCursor DEALLOCATE StudentCursor SET @err7=@@ERROR --判断是否执行成功 IF (@err1 =0 and @err2=0 and @err3=0 and @err4=0 and @err5=0 and @err6=0 and @err7=0) --提交事务 COMMIT TRANSACTION ELSE --事务回滚 ROLLBACK TRANSACTION END
【删除触发器(Delete Trigger)】
当删除表中记录时触发
先把要删除的记录放到Deleted临时表中,然后,再删除。
例如:
USE [BasicDataSystem] GO /****** Object: Trigger [dbo].[TR_TeachCourseLink_D] Script Date: 2013/1/2 19:29:42 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON G