加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

探索SQL Server元数据(二)

发布时间:2020-12-12 09:07:04 所属栏目:MsSql教程 来源:网络整理
导读:背景 上一篇中,我介绍了SQL Server 允许访问数据库的元数据,为什么有元数据,如何使用元数据。这一篇中我会介绍如何进一步找到各种有价值的信息。以触发器为例,因为它们往往一起很多问题。 那么如何找到触发器的数据? 以sys.system_views is表开始。让我们

背景

  上一篇中,我介绍了SQL Server 允许访问数据库的元数据,为什么有元数据,如何使用元数据。这一篇中我会介绍如何进一步找到各种有价值的信息。以触发器为例,因为它们往往一起很多问题。

那么如何找到触发器的数据?

  以sys.system_viewsis表开始。让我们查询出数据库中使用触发器的信息。可以告知你当前SQL Server版本中有什么触发器。

SELECT schema_name(schema_ID)++FROM sys.system_views WHERE name LIKE <span style="color: #800000">'<span style="color: #800000">%trigger%<span style="color: #800000">'

sys.dm_exec_trigger_stats

sys.server_trigger_events

sys.server_triggers

sys.trigger_event_types

sys.trigger_events

sys.triggers

(6 row(s) affected)

  其中sys.triggers看起来信息很多,它又包含什么列?下面这个查询很容易查到:

SELECT Thecol.name+ ++ CASE WHEN TheCol.is_nullable=<span style="color: #800080">1 THEN <span style="color: #800000">'<span style="color: #800000"> NULL<span style="color: #800000">' ELSE <span style="color: #800000">'<span style="color: #800000"> NOT NULL<span style="color: #800000">' END <span style="color: #0000ff">as<span style="color: #000000"> Column_Information

FROM sys.system_views AS TheView

INNER JOIN sys.system_columns AS TheCol

ON TheView.object_ID</span>=<span style="color: #000000"&gt;TheCol.Object_ID

WHERE TheView.name = <span style="color: #800000">'<span style="color: #800000">triggers<span style="color: #800000">'<span style="color: #000000">

ORDER BY column_ID;

结果如下:

name nvarchar NOT NULL

object_id int NOT NULL

parent_class tinyint NOT NULL

parent_class_desc nvarchar NULL

parent_id int NOT NULL

type char NOT NULL

type_desc nvarchar NULL

create_date datetime NOT NULL

modify_date datetime NOT NULL

is_ms_shipped bit NOT NULL

is_disabled bit NOT NULL

is_not_for_replication bit NOT NULL

is_instead_of_trigger bit NOT NULL

因此我们多这个信息有了更好的理解,有了一个目录的目录。这个概念有点让人头晕,但是另一方面,它也是相当简单的。我们能够查出元数据,再找个查询中,需要做的就是改变这个单词‘triggers’来查找你想要的视图名称。.

在2012及其以后版本,可以使用一个新的表值函数极大地简化上述查询,并可以避免各种连接。在下面的查询中,我们将查找sys.triggers 视图 中的列。可以使用相同的查询通过更改字符串中的对象名称来获取任何视图的定义。

+ ++ CASE WHEN is_nullable=<span style="color: #800080">1 THEN <span style="color: #800000">'<span style="color: #800000"> NULL<span style="color: #800000">' ELSE <span style="color: #800000">'<span style="color: #800000"> NOT NULL<span style="color: #800000">' END <span style="color: #0000ff">as<span style="color: #000000"> Column_Information

FROM sys.dm_exec_describe_first_result_set

( N<span style="color: #800000">'<span style="color: #800000">SELECT * FROM sys.triggers;<span style="color: #800000">',NULL,<span style="color: #800080">0<span style="color: #000000">) AS f

ORDER BY column_ordinal;

查询结果如下:

----------------------------------------<span style="color: #000000">

name nvarchar(<span style="color: #800080">128<span style="color: #000000">) NOT NULL

object_id <span style="color: #0000ff">int<span style="color: #000000"> NOT NULL

parent_class tinyint NOT NULL

parent_class_desc nvarchar(<span style="color: #800080">60<span style="color: #000000">) NULL

parent_id <span style="color: #0000ff">int<span style="color: #000000"> NOT NULL

type <span style="color: #0000ff">char(<span style="color: #800080">2<span style="color: #000000">) NOT NULL

type_desc nvarchar(<span style="color: #800080">60<span style="color: #000000">) NULL

create_date datetime NOT NULL

modify_date datetime NOT NULL

is_ms_shipped bit NOT NULL

is_disabled bit NOT NULL

is_not_for_replication bit NOT NULL

is_instead_of_trigger bit NOT NULL

sys.dm_exec_describe_first_result_set函数的最大优势在于你能看到任何结果的列,不仅仅是表和视图、存储过程或者贬值函数。

为了查出任何列的信息,你可以使用稍微修改的版本,只需要改变代码中的字符串'sys.triggers'即可,如下:

Declare @TheParamater nvarchar(Select @TheParamater = <span style="color: #800000">'<span style="color: #800000">sys.triggers<span style="color: #800000">'<span style="color: #000000">

Select @TheParamater = <span style="color: #800000">'<span style="color: #800000">SELECT * FROM <span style="color: #800000">' +<span style="color: #000000"> @TheParamater

SELECT

name+ <span style="color: #800000">' <span style="color: #800000">'+<span style="color: #000000"> system_type_name

+ CASE WHEN is_nullable=<span style="color: #800080">1 THEN <span style="color: #800000">'<span style="color: #800000"> NULL<span style="color: #800000">' ELSE <span style="color: #800000">'<span style="color: #800000"> NOT NULL<span style="color: #800000">' END <span style="color: #0000ff">as<span style="color: #000000"> Column_Information

FROM sys.dm_exec_describe_first_result_set

( @TheParamater,<span style="color: #800080">0<span style="color: #000000">) AS f

ORDER BY column_ordinal;

但是当然一个触发器是首先是一个对象,因此一定在sys.objects?

  在我们使用sys.triggers的信息之前,需要来重复一遍,所有的数据库对象都存在于sys.objects中,在SQL Server 中的对象包括以下:聚合的CLR函数,check 约束,SQL标量函数,CLR标量函数,CLR表值函数,SQL内联表值函数,内部表,SQL存储过程,CLR存储过程,计划指南,主键约束,老式规则,复制过滤程序,系统基础表,同义词,序列对象,服务队列,CLR DML 触发器,SQL表值函数,表类型,用户自定义表,唯一约束,视图和扩展存储过程等。

  触发器是对象所以基础信息一定保存在sys.objects。不走运的是,有时我们需要额外的信息,这些信息可以通过目录视图查询。这些额外数据有是什么呢?

  修改我们使用过的查询,来查询sys.triggers的列,这次我们会看到额外信息。这些额外列是来自于sys.objects。

SELECT coalesce(trigger_column.name,FROM

(SELECT Thecol.name

FROM sys.system_views AS TheView

INNER JOIN sys.system_columns AS TheCol

  ON TheView.object_ID</span>=<span style="color: #000000"&gt;TheCol.Object_ID

WHERE TheView.name = <span style="color: #800000">'<span style="color: #800000">triggers<span style="color: #800000">'<span style="color: #000000">) trigger_column

FULL OUTER JOIN

(SELECT Thecol.name

FROM sys.system_views AS TheView

INNER JOIN sys.system_columns AS TheCol

  ON TheView.object_ID</span>=<span style="color: #000000"&gt;TheCol.Object_ID

WHERE TheView.name = <span style="color: #800000">'<span style="color: #800000">objects<span style="color: #800000">'<span style="color: #000000">) object_column

ON trigger_column.name=<span style="color: #000000">object_column.name

查询结果:

In_Sys_Triggers In_Sys_Objects

------------------------------ ----------------------<span style="color: #000000">

name name

object_id object_id

NOT INCLUDED principal_id

NOT INCLUDED schema_id

NOT INCLUDED parent_object_id

type type

type_desc type_desc

create_date create_date

modify_date modify_date

is_ms_shipped is_ms_shipped

NOT INCLUDED is_published

NOT INCLUDED is_schema_published

is_not_for_replication NOT INCLUDED

is_instead_of_trigger NOT INCLUDED

parent_id NOT INCLUDED

is_disabled NOT INCLUDED

parent_class NOT INCLUDED

parent_class_desc NOT INCLUDED

以上这些让我们知道在sys.triggers的额外信息,但是因为它始终是表的子对象,所以有些不相关信息是不会展示在这些指定的视图或者sys.triggers中的。现在就要带大家去继续找找这些信息。

触发器的问题

  触发器是有用的,但是因为它们在SSMS对象资源管理器窗格中不是可见的,所以一般用来提醒错误。触发器有时候会有些微妙的地方让其出问题,比如,当导入过程中禁用了触发器,并且由于某些原因他们没有重启。

下面是一个关于触发器的简要提醒:

  触发器可以在视图,表或者服务器上,任何这些对象上都可以有超过1个触发器。普通的DML触发器能被定义来执行替代一些数据修改(Insert,Update或者Delete)或者在数据修改之后执行。每一个触发器与只与一个对象管理。DDL触发器与数据库关联或者被定义在服务器级别,这类触发器一般在Create,Alter或者Drop这类SQL语句执行后触发。

  像DML触发器一样,可以有多个DDL触发器被创建在同一个T-SQL语句上。一个DDL触发器和语句触发它的语句在同一个事务中运行,所以除了Alter DATABASE之外都可以被回滚。DDL触发器运行在T-SQL语句执行完毕后,也就是不能作为Instead OF触发器使用。

  两种触发器都与事件相关,在DML触发器中,包含INSERT,UPDATE,和DELETE,然而很多事件都可以与DDL触发器关联,稍后我们将了解。

在数据库中列出触发器

那么怎么获取触发器列表?下面我在AdventureWorks数据库中进行查询,注意该库的视图中没有触发器。

第一个查询所有信息都在sys.triggers 的目录视图中。

name AS TriggerName,coalesce(object_schema_name(parent_ID)+<span style="color: #800000">'
<span style="color: #800000">.
<span style="color: #800000">'

+object_name(parent_ID),<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;Database (</span><span style="color: #800000"&gt;'</span>+db_name()+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;)</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;) AS TheParent

FROM sys.triggers;

TriggerName TheParent

------------------------------ ----------------------------------------<span style="color: #000000">

ddlDatabaseTriggerLog Database (AdventureWorks2012)

dEmployee HumanResources.Employee

iuPerson Person.Person

iPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail

uPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail

uPurchaSEOrderHeader Purchasing.PurchaSEOrderHeader

iduSalesOrderDetail Sales.SalesOrderDetail

uSalesOrderHeader Sales.SalesOrderHeader

dVendor Purchasing.Vendor

iWorkOrder Production.WorkOrder

uWorkOrder Production.WorkOrder

  我使用元数据函数db_name()使SQL保持简单。db_name()告诉我数据库的名称。object_schema_name()用来查询object_ID代表的对象的架构,以及object_name()查询对象名称。这些对对象的引用指向触发器的所有者,触发器可以是数据库本身,也可以是表:服务器触发器有自己的系统视图,稍后我会展示。

如果想要看到所有触发器,那么我们最好使用sys.objects 视图:

SELECT name TriggerName,object_schema_name(parent_object_ID)+
+<span style="color: #000000"&gt;object_name(parent_object_ID) AS TheParent

        FROM   sys.objects

       WHERE  OBJECTPROPERTYEX(object_id,</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;IsTrigger</span><span style="color: #800000"&gt;'</span>) = <span style="color: #800080"&gt;1</span></pre>

注意,输出不包含数据库级别的触发器,因为所有的DML触发器都在sys.objects视图中,但是你会漏掉在sys.triggers视图中的触发器。

上面查询结果:

------------------------------ -------------------------------<span style="color: #000000">

dEmployee HumanResources.Employee

iuPerson Person.Person

iPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail

uPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail

uPurchaSEOrderHeader Purchasing.PurchaSEOrderHeader

iduSalesOrderDetail Sales.SalesOrderDetail

uSalesOrderHeader Sales.SalesOrderHeader

dVendor Purchasing.Vendor

iWorkOrder Production.WorkOrder

uWorkOrder Production.WorkOrder

我的表和视图有多少个触发器?

我想知道每个表有多少个触发器,并且什么情况下触发它们。下面我们列出了具有触发器的表以及每个事件的触发器数量。每个表或者视图对于触发器行为都有一个INSTEAD OF 触发器,可能是UPDATE,DELETE,或者 INSERT

。但是一个表可以有多个AFTER触发器行为。这些将展示在下面的查询中(排除视图):

convert(CHAR(<span style="color: #800080">32
),coalesce(object_schema_name(parent_ID)+<span style="color: #800000">'
<span style="color: #800000">.
<span style="color: #800000">'

+object_name(parent_ID),<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;Database (</span><span style="color: #800000"&gt;'</span>+db_name()+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;)</span><span style="color: #800000"&gt;'</span>)) AS <span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;Table</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;,triggers,[KD1] [AC2] 

convert(SMALLINT,objectpropertyex(parent_ID,N<span style="color: #800000">'<span style="color: #800000">TABLEDeleteTriggerCount<span style="color: #800000">')) AS <span style="color: #800000">'<span style="color: #800000">Delete<span style="color: #800000">'<span style="color: #000000">,convert(SMALLINT,N<span style="color: #800000">'<span style="color: #800000">TABLEInsertTriggerCount<span style="color: #800000">')) AS <span style="color: #800000">'<span style="color: #800000">Insert<span style="color: #800000">'<span style="color: #000000">,N<span style="color: #800000">'<span style="color: #800000">TABLEUpdateTriggerCount<span style="color: #800000">')) AS <span style="color: #800000">'<span style="color: #800000">Update<span style="color: #800000">'<span style="color: #000000">

FROM (SELECT count(*<span style="color: #000000">) AS triggers,parent_ID FROM sys.triggers

  WHERE objectpropertyex(parent_ID,N</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;IsTable</span><span style="color: #800000"&gt;'</span>) =<span style="color: #800080"&gt;1</span><span style="color: #000000"&gt;

     GROUP BY parent_ID

      )TablesOnly;

--<span style="color: #000000">查询结果如下:

Table triggers Delete Insert Update

-------------------------------- ----------- ------ ------ ------<span style="color: #000000">

Purchasing.Vendor <span style="color: #800080">1 <span style="color: #800080">0 <span style="color: #800080">0 <span style="color: #800080">0<span style="color: #000000">

Production.WorkOrder <span style="color: #800080">2 <span style="color: #800080">0 <span style="color: #800080">1 <span style="color: #800080">1<span style="color: #000000">

Purchasing.PurchaSEOrderDetail <span style="color: #800080">2 <span style="color: #800080">0 <span style="color: #800080">1 <span style="color: #800080">1<span style="color: #000000">

Purchasing.PurchaSEOrderHeader <span style="color: #800080">1 <span style="color: #800080">0 <span style="color: #800080">0 <span style="color: #800080">1<span style="color: #000000">

Sales.SalesOrderDetail <span style="color: #800080">1 <span style="color: #800080">1 <span style="color: #800080">1 <span style="color: #800080">1<span style="color: #000000">

HumanResources.Employee <span style="color: #800080">1 <span style="color: #800080">0 <span style="color: #800080">0 <span style="color: #800080">0<span style="color: #000000">

Sales.SalesOrderHeader <span style="color: #800080">1 <span style="color: #800080">0 <span style="color: #800080">0 <span style="color: #800080">1<span style="color: #000000">

Person.Person <span style="color: #800080">1 <span style="color: #800080">0 <span style="color: #800080">1 <span style="color: #800080">1<span style="color: #000000">

(<span style="color: #800080">8 row(s) affected)

如果超过一个触发器被触发在一个表上,它们不保证顺序,当然也可以使用sp_settriggerorder来控制顺序。通过使用objectpropertyex()元数据函数,需要根据事件输入参数‘ExecIsLastDeleteTrigger’,‘ExecIsLastInsertTrigger’ 或者 ‘ExecIsLastUpdateTrigger’来确认谁是最后一个执行的触发器 。为了得到第一个触发器,酌情使用ObjectPropertyEx() 元数据函数,需要输入参数 ‘ExecIsFirstDeleteTrigger’,‘ExecIsFirstInsertTrigger’ 或者 ‘ExecIsFirstUpdateTrigger’。

因此我们现在知道了表有哪些触发器,哪些事件触发这些触发器。可以使用objectpropertyex()元数据函数,这个函数返回很多不同信息,根据指定的参数不同。通过查看MSDN中的文档,查看其中的一个文档是否有助于元数据查询,总是值得检查的。

触发器何时触发事件?

让我们看一下这些触发器,DML触发器可以在所有其他时间发生后触发,但是可以在约束被处理前并且触发INSTEAD OF触发动作。下面我们就来看看所有的触发的到底是AFTER 还是INSTEAD OF 触发器,有事什么时间触发了触发器。

SELECT

convert(CHAR(<span style="color: #800080">25<span style="color: #000000">),name) AS triggerName,convert(CHAR(<span style="color: #800080">32),<span style="color: #800000">'<span style="color: #800000">Database (<span style="color: #800000">'+db_name()+<span style="color: #800000">'<span style="color: #800000">)<span style="color: #800000">'<span style="color: #000000">)) AS TheParent,is_disabled,CASE WHEN is_instead_of_trigger=<span style="color: #800080">1 THEN <span style="color: #800000">'<span style="color: #800000">INSTEAD OF <span style="color: #800000">' ELSE <span style="color: #800000">'<span style="color: #800000">AFTER <span style="color: #800000">'<span style="color: #000000"> END

   </span>+Stuff (--<span style="color: #0000ff"&gt;get</span> a list of events <span style="color: #0000ff"&gt;for</span><span style="color: #000000"&gt; each trigger

    (SELECT </span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;,</span><span style="color: #800000"&gt;'</span>+<span style="color: #000000"&gt;type_desc FROM sys.trigger_events te

       WHERE te.object_ID</span>=<span style="color: #000000"&gt;sys.triggers.object_ID

     FOR XML PATH(</span><span style="color: #800000"&gt;''</span>),TYPE).value(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;.</span><span style="color: #800000"&gt;'</span>,<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;varchar(max)</span><span style="color: #800000"&gt;'</span>),<span style="color: #800080"&gt;1</span>,<span style="color: #800080"&gt;2</span>,<span style="color: #800000"&gt;''</span><span style="color: #000000"&gt;) AS events

FROM sys.triggers;

结果如下:

------------------------- -------------------------------- ----------- ---------<span style="color: #000000">

ddlDatabaseTriggerLog Database (AdventureWorks2012) <span style="color: #800080">1<span style="color: #000000"> AFTER CREATE_TABLE,ALTER_TABLE,DROP_TABLE,CREATE_VIEW,ALTER_VIEW,DROP_VIEW,CREATE_INDEX,ALTER_INDEX,DROP_INDEX,CREATE_XML_INDEX,ALTER_FULLTEXT_INDEX,CREATE_FULLTEXT_INDEX,DROP_FULLTEXT_INDEX,CREATE_SPATIAL_INDEX,CREATE_STATISTICS,UPDATE_STAT

t_AB dbo.AB <span style="color: #800080">0<span style="color: #000000"> INSTEAD OF INSERT

dEmployee HumanResources.Employee <span style="color: #800080">0<span style="color: #000000"> INSTEAD OF DELETE

iuPerson Person.Person <span style="color: #800080">0<span style="color: #000000"> AFTER INSERT,UPDATE

iPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail <span style="color: #800080">0<span style="color: #000000"> AFTER INSERT

uPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail <span style="color: #800080">0<span style="color: #000000"> AFTER UPDATE

uPurchaSEOrderHeader Purchasing.PurchaSEOrderHeader <span style="color: #800080">0<span style="color: #000000"> AFTER UPDATE

iduSalesOrderDetail Sales.SalesOrderDetail <span style="color: #800080">0<span style="color: #000000"> AFTER INSERT,DELETE

uSalesOrderHeader Sales.SalesOrderHeader <span style="color: #800080">0<span style="color: #000000"> AFTER UPDATE

dVendor Purchasing.Vendor <span style="color: #800080">0<span style="color: #000000"> INSTEAD OF DELETE

iWorkOrder Production.WorkOrder <span style="color: #800080">0<span style="color: #000000"> AFTER INSERT

uWorkOrder Production.WorkOrder <span style="color: #800080">0 AFTER UPDATE

As you will notice,we used here to make a list of the events for each trigger to make it easier to read. These events were pulled from the sys.trigger_events view using a correlated subquery.

注意到我们使用了来列出事件的每一个触发器,更容易读取理解。sys.trigger_events使用相关子查询来查询这些事件。

触发器的多长?

许多数据库人员不赞成冗长触发器的定义,但他们可能会发现,根据定义的长度排序的触发器列表是研究数据库的一种有用方法。

SELECT convert(CHAR(),coalesce(object_schema_name(t.object_ID)+,</span>+<span style="color: #000000"&gt;name) AS TheTrigger,<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;Database (</span><span style="color: #800000"&gt;'</span>+db_name()+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;)</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;)) AS theParent,len(definition) AS length </span>--<span style="color: #000000"&gt;the length of the definition

FROM sys.SQL_modules m

INNER JOIN sys.triggers t

ON t.object_ID</span>=<span style="color: #000000"&gt;m.object_ID

ORDER BY length DESC;

访问sys.SQL_modules视图可以查看触发器定义的SQL DDL,并按大小顺序列出它们,最上面是最大的。

结果:

-------------------------------- -------------------------------- --------<span style="color: #000000">

Sales.iduSalesOrderDetail Sales.SalesOrderDetail <span style="color: #800080">3666<span style="color: #000000">

Sales.uSalesOrderHeader Sales.SalesOrderHeader <span style="color: #800080">2907<span style="color: #000000">

Purchasing.uPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail <span style="color: #800080">2657<span style="color: #000000">

Purchasing.iPurchaSEOrderDetail Purchasing.PurchaSEOrderDetail <span style="color: #800080">1967<span style="color: #000000">

Person.iuPerson Person.Person <span style="color: #800080">1498<span style="color: #000000">

ddlDatabaseTriggerLog Database (AdventureWorks2012) <span style="color: #800080">1235<span style="color: #000000">

Purchasing.dVendor Purchasing.Vendor <span style="color: #800080">1103<span style="color: #000000">

Production.uWorkOrder Production.WorkOrder <span style="color: #800080">1103<span style="color: #000000">

Purchasing.uPurchaSEOrderHeader Purchasing.PurchaSEOrderHeader <span style="color: #800080">1085<span style="color: #000000">

Production.iWorkOrder Production.WorkOrder <span style="color: #800080">1011<span style="color: #000000">

HumanResources.dEmployee HumanResources.Employee <span style="color: #800080">604

好吧,我可能太挑剔了,不太喜欢太长的,但是逻辑有时候会很长。事实上,前三名在我看来是不可靠的,尽管我总是倾向于尽可能少地使用触发器。

这些触发器访问了多少对象

在代码中,每个触发器要访问多少对象(比如表和函数)?

我们只需要检查表达式依赖项。这个查询使用一个视图来列出“软”依赖项(如触发器、视图和函数)。

</span>+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;.</span><span style="color: #800000"&gt;'</span>,<span style="color: #800000"&gt;''</span>)+convert(CHAR(<span style="color: #800080"&gt;32</span><span style="color: #000000"&gt;),name) AS TheTrigger,count(</span>*<span style="color: #000000"&gt;) AS Dependencies

FROM sys.triggers

INNER JOIN sys.SQL_Expression_dependencies

ON [referencing_id]=<span style="color: #000000">object_ID

GROUP BY name,parent_id

ORDER BY count(*<span style="color: #000000">) DESC;
--结果:

TheTrigger Dependencies

---------------------------------------- ------------<span style="color: #000000">

Sales.iduSalesOrderDetail <span style="color: #800080">7<span style="color: #000000">

Sales.uSalesOrderHeader <span style="color: #800080">7<span style="color: #000000">

Purchasing.iPurchaSEOrderDetail <span style="color: #800080">5<span style="color: #000000">

Purchasing.uPurchaSEOrderDetail <span style="color: #800080">5<span style="color: #000000">

Purchasing.uPurchaSEOrderHeader <span style="color: #800080">3<span style="color: #000000">

Production.iWorkOrder <span style="color: #800080">3<span style="color: #000000">

Production.uWorkOrder <span style="color: #800080">3<span style="color: #000000">

dbo.t_AB <span style="color: #800080">2<span style="color: #000000">

Purchasing.dVendor <span style="color: #800080">2<span style="color: #000000">

Person.iuPerson <span style="color: #800080">2<span style="color: #000000">

ddlDatabaseTriggerLog <span style="color: #800080">1

居然有两个触发器有7个依赖!让我们就Sales.iduSalesOrderDetail来实际看一下,有哪些依赖。

特定触发器访问或者写入哪些对象?

我们可以列出触发器在代码中引用的所有对象

convert(<span style="color: #0000ff">char
(<span style="color: #800080">32
),name) <span style="color: #0000ff">as
<span style="color: #000000"> TheTrigger,convert(
<span style="color: #0000ff">char
(<span style="color: #800080">32
),coalesce([referenced_server_name]+<span style="color: #800000">'
<span style="color: #800000">.
<span style="color: #800000">'
,<span style="color: #800000">''
<span style="color: #000000">)

        </span>+coalesce([referenced_database_name]+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;.</span><span style="color: #800000"&gt;'</span>,<span style="color: #800000"&gt;''</span><span style="color: #000000"&gt;)

   </span>+coalesce([referenced_schema_name]+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;.</span><span style="color: #800000"&gt;'</span>,<span style="color: #800000"&gt;''</span>)+<span style="color: #000000"&gt;[referenced_entity_name])
 </span><span style="color: #0000ff"&gt;as</span><span style="color: #000000"&gt; referencedObject

FROM sys.triggers

INNER JOIN sys.SQL_Expression_dependencies

ON [referencing_id]=<span style="color: #000000">object_ID

WHERE name LIKE <span style="color: #800000">'<span style="color: #800000">iduSalesOrderDetail<span style="color: #800000">'<span style="color: #000000">;

--<span style="color: #000000">查询结果:

TheTrigger referencedObject

-------------------------------- --------------------------------<span style="color: #000000">

iduSalesOrderDetail Sales.Customer

iduSalesOrderDetail Person.Person

iduSalesOrderDetail Sales.SalesOrderDetail

iduSalesOrderDetail Sales.SalesOrderHeader

iduSalesOrderDetail Production.TransactionHistory

iduSalesOrderDetail dbo.uspLogError

iduSalesOrderDetail dbo.uspPrintError

触发器里有什么代码?

现在让我们通过检查触发器的源代码来确认这一点。.

SELECT OBJECT_DEFINITION ( object_id() );

我们之前的查询是正确的,扫描源码可知所有的依赖项。大量依赖项表名对于数据库的重构等需要非常小心,例如,修改一个基础表的列。

据需要做什么,您可能希望检查来自元数据视图的定义,而不是使用OBJECT_DEFINITION函数。

FROM sys.SQL_modules m

INNER JOIN sys.triggers t

ON t.object_ID</span>=<span style="color: #000000"&gt;m.object_ID

WHERE t.object_ID=object_id(<span style="color: #800000">'<span style="color: #800000">sales.iduSalesOrderDetail<span style="color: #800000">');

搜索触发器的代码

There are always plenty of ways of using the metadata views and functions. I wonder if all these triggers are executing that uspPrintError procedure?

有很多使用元数据视图和函数的方法。想知道是否所有这些触发器都执行uspPrintError存储过程?

/*?在所有触发器中搜索字符串 */

<div class="cnblogs_code">

SELECT convert(CHAR(),coalesce(object_schema_name(object_ID)+,</span>+name) AS TheTrigger,<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;...</span><span style="color: #800000"&gt;'</span>+substring(definition,hit-<span style="color: #800080"&gt;20</span>,<span style="color: #800080"&gt;120</span>) +<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;...</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;

FROM

(SELECT name,definition,t.object_ID,charindex(<span style="color: #800000">'<span style="color: #800000">EXECUTE [dbo].[uspPrintError]<span style="color: #800000">'<span style="color: #000000">,definition) AS hit

FROM sys.SQL_modules m

 INNER JOIN sys.triggers t

   ON t.object_ID</span>=<span style="color: #000000"&gt;m.object_ID)f

WHERE hit><span style="color: #800080">0;

结果如图:

8个引用正在执行这个过程。我们在sys.SQL_modules中搜索了所有的定义可以找到一个特定的字符串,这种方式很慢很暴力,但是它是有效的!

在所有对象中搜索字符串

我想知道除了触发器之外是否还有其他对象调用这个过程?我们稍微修改查询以搜索sys.objects视图,而不是sys.triggers,以搜索所有具有与之关联的代码的对象。我们还需要显示对象的类型

/*?在所有对象中搜索字符串 */

SELECT convert(CHAR(),</span>+object_name(object_ID)) AS TheObject,type_desc,<span style="color: #800080"&gt;120</span>)+<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;...</span><span style="color: #800000"&gt;'</span> <span style="color: #0000ff"&gt;as</span><span style="color: #000000"&gt; TheExtract

FROM

(SELECT type_desc,o.object_ID,charindex(<span style="color: #800000">'<span style="color: #800000">uspPrintError<span style="color: #800000">'<span style="color: #000000">,definition) AS hit

FROM sys.SQL_modules m

 INNER JOIN sys.objects o

   ON o.object_ID</span>=<span style="color: #000000"&gt;m.object_ID)f

WHERE hit><span style="color: #800080">0;

查询结果如下图:

?From this output we can see that,other than the procedure itself where it is defined,and the triggers,only dbo.uspLogError is executing the uspPrintError procedure. (see the first column,second line down)

从这个输出中我们可以看到,除了在定义它的过程本身之外,还有触发器,只有dbo.uspLogError正在执行uspPrintError过程。(见第一列,第二行往下)

列出服务器级触发器及其定义

我们可以通过系统视图了解它们吗?嗯,是的。以下是列出服务器触发器及其定义的语句

FROM sys.server_SQL_modules m

INNER JOIN sys.server_triggers t

ON t.object_ID=m.object_ID;

注意,只能看到有权限看的触发器

总结

  本文讨论过触发器,并且你能查出触发器,以及潜在的问题。这里并没有针对关于触发器的查询提供一个全面的工具箱,因为我只是使用触发器作为示例来展示在查询系统视图时可能使用的一些技术。在我们学习了索引、列和参数之后,我们将回到触发器,并了解了编写访问系统视图和information schema视图的查询的一些日常用途。表是元数据的许多方面的基础。它们是几种类型的对象的父类,其他元数据如索引是表的属性。我们正在慢慢地努力去发现所有关于表的信息。期待下期

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读