获取包含 INSERT 的存储过程的“列表”,而无需命名所涉及的列

use*_*979 1 sql-server stored-procedures t-sql sql-server-2016

作为某些增强功能的一部分,750 多个表中添加了一个新列。现在我的问题是在将近 3000 多个存储过程中,一些旧的 INSERT 没有命名列。

有什么办法可以得到所有没有列名插入的存储过程的“列表”?

我试过了:

SELECT OBJECT_NAME(object_id)
FROM sys.sql_modules
WHERE definition LIKE '%insert into%' 
AND definition NOT LIKE '%) value%'
AND definition NOT LIKE '%)%' + CHAR(10) + '%value%'
AND definition NOT LIKE '%)%' + CHAR(13) + '%value%'
AND definition LIKE '%value%' 
Run Code Online (Sandbox Code Playgroud)

但它仍然错过了很多。

PS - 上面的查询也返回 Insert Into (ColumnNames) SELECT 场景,这是我不想要的。

Mic*_*een 5

有一个名为sys.dm_sql_referenced_entities的 DMV 。它返回is_insert_all这样记录的列

1 = 对象在没有列列表的 INSERT 语句中使用(仅限对象级别)。

这似乎就是你要找的。

下面是它在实践中的一个例子。首先我们将创建一个简单的单列表

drop table if exists dbo.T1;
go
create table dbo.T1(c int);
Run Code Online (Sandbox Code Playgroud)

现在有两个存储过程,一个显式引用列,另一个没有。

create or alter procedure dbo.p_named
as
begin
    insert dbo.T1(c)  -- columns are listed
    select 1;
end
go

create or alter procedure dbo.p_not_named
as
begin
    insert dbo.T1   -- no column list
    select 2;
end
go
Run Code Online (Sandbox Code Playgroud)

DMV 是一个表值函数。因此,可以使用CROSS APPLY语法调用它。传递给该函数的过程名称可以从目录视图sys.procedures 中获得。此 DMV 的文档说明

当引用类为 OBJECT 时,需要 schema_name。

我们可以使用名为SCHEMA_NAME()的内置元数据函数轻松获取模式名称。把它们放在一起,我们得到

select
    p.name, is_insert_all -- other columns exist
from sys.procedures as p
cross apply sys.dm_sql_referenced_entities(CONCAT(SCHEMA_NAME(p.schema_id), '.', p.name), 'OBJECT');
Run Code Online (Sandbox Code Playgroud)

哪个返回这个

name          is_insert_all
------------- -------------
p_named       0
p_named       0
p_not_named   1
Run Code Online (Sandbox Code Playgroud)