SQL 查询查找未命名列的 INSERT 存储过程

标签 sql sql-server stored-procedures

我是大型开发团队的最后一名成员,负责将大型现有系统移交给新团队。作为迁移的一部分,ID 列将被添加到数据库中的每个表中(即使该表已经有一个)。问题是在数百个存储过程中,一些旧的 INSERTS 没有命名列:

INSERT INTO tablename VALUES (blah, blah, blah)

当然,这些会随着添加的新列而中断,因为表中的列数与 INSERT 中的列数不匹配。我需要更改所有 INSERT

没问题,除了我首先需要找到它们。此查询返回超过 900 个结果和太多误报(因为它返回命名列和未命名列的 INSERT):

SELECT OBJECT_NAME(object_id)
FROM sys.sql_modules
WHERE definition LIKE '%insert into%' 
  AND OBJECT_NAME(object_id) NOT LIKE 'MSmerge%'
ORDER BY OBJECT_NAME(object_id)

这个返回了一个不错的小数字,但错过了一些我知道是不好的:

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%' 
  AND OBJECT_NAME(object_id) NOT LIKE 'MSmerge%'

这是上次查询错过的存储过程的一部分:

BEGIN
    IF @someFlag = 1
        INSERT INTO tablename VALUES (@myCode, @myYear, @myMonth, 1, 1, 0)
    ELSE
        INSERT INTO tablename VALUES (@myCode, @myYear, @myMonth, 1, 0, 1)
END

有没有办法可靠地找到我需要修复的存储过程?

最佳答案

对于本例sp_refreshsqlmodule非常有用。它不仅按照文档所述更新元数据,而且还进行大量检查。它可以检测 View 、存储过程、触发器和函数中的大量错误。

以下存储过程在数据库中的所有 SQL 模块上调用 sp_refreshsqlmodule 并打印出它发现的所有错误:

CREATE PROCEDURE [dbo].[RefreshAllModules]
AS

    DECLARE m CURSOR FOR
    SELECT '[' + s.name + ']'  + '.[' + o.name + ']' AS name, o.type_desc
    FROM 
        sys.sql_modules m
        INNER JOIN sys.objects o 
            on m.object_id = o.object_id
        INNER JOIN sys.schemas s
            on o.schema_id = s.schema_id
    WHERE
        m.is_schema_bound = 0
    OPEN m
    DECLARE  @name sysname, @type_desc sysname
    FETCH NEXT FROM m into @name, @type_desc
    WHILE  @@FETCH_STATUS = 0
    BEGIN
        BEGIN TRY
            EXEC sp_refreshsqlmodule @name
        END TRY

        BEGIN CATCH
            IF  @@TRANCOUNT > 0 ROLLBACK
            PRINT ERROR_MESSAGE()
            PRINT  @type_desc + ': ' +  @name
            PRINT ''
        END CATCH
        FETCH NEXT FROM m INTO @name,  @type_desc
    END
    CLOSE m
    DEALLOCATE m
GO

例如,假设您有下表和存储过程:

CREATE TABLE T
(
    name varchar(50) NOT NULL
)
GO

CREATE PROCEDURE p
AS
    INSERT INTO T VALUES ('John Doe') 

GO

稍后,您更改表格:

ALTER TABLE t ADD id int;

现在,存储过程无效。但您可以检测到它正在执行 RefreshAllModules:

EXEC RefreshAllModules

哪些输出:

Column name or number of supplied values does not match table definition. SQL_STORED_PROCEDURE: [dbo].[p]

关于SQL 查询查找未命名列的 INSERT 存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49241339/

相关文章:

java - 通过 Java 类声明 OUT 参数

mysql - 有没有更好的方法来按部门获取最高(工资)并确保只有平均(工资)> 50,000 的部门?

Mysql 查询从行中删除不需要的字母

python - python 2.7 中的 MSSQL

sql - 平均模式 - 在 SQL Server 中需要帮助进行计算

sql-server - SQL事务死锁

mysql - 如何使用 MySQL 根据第一个表中特定列中的值从 2 个表中获取记录数

php - MySQL 多重左连接与可能的空记录

sql-server - 将数据类型 numeric 转换为 int 时出错

unit-testing - 使用 Sqlite 将存储过程添加到内存数据库