Sql server 更改现有约束/规则/程序上的引用\u标识符

Sql server 更改现有约束/规则/程序上的引用\u标识符,sql-server,tsql,sql-server-2008-r2,sql-server-2012,quoted-identifier,Sql Server,Tsql,Sql Server 2008 R2,Sql Server 2012,Quoted Identifier,我目前正在使用2008-r2服务器上的一个旧ish数据库,该数据库使用了许多对象,这些对象是在Quoted Identifier设置为off时创建的 我主要关注这些类型: CHECK_CONSTRAINT DEFAULT_CONSTRAINT RULE SQL_SCALAR_FUNCTION SQL_STORED_PROCEDURE SQL_TRIGGER VIEW 我现在正试图更改引用的标识符设置,这让我立即感到困惑,因为我发现我甚至不能更改约束 对于限制:我认为我必须以某种方式进行临时克隆

我目前正在使用2008-r2服务器上的一个旧ish数据库,该数据库使用了许多对象,这些对象是在Quoted Identifier设置为off时创建的

我主要关注这些类型:

CHECK_CONSTRAINT
DEFAULT_CONSTRAINT
RULE
SQL_SCALAR_FUNCTION
SQL_STORED_PROCEDURE
SQL_TRIGGER
VIEW
我现在正试图更改引用的标识符设置,这让我立即感到困惑,因为我发现我甚至不能更改约束


对于限制:我认为我必须以某种方式进行临时克隆/复制,删除原始副本,然后使用副本和设置为ON的引用的_标识符重新创建它们,但我真的不知道如何做到这一点或如何自动化这一点,因为我的SQL技能有限。有人能帮我吗?或者有人知道更简单的替代方法吗?

为该数据库编写脚本,删除所有引用的标识符,从脚本中重新创建数据库并重新导入数据(MS SS中包含该向导)

这种解决方案可能有很多味道。使用动态sql/smo技术解决了类似的问题:

我在一个安装过程中遇到了一个错误,导致引用的标识符在大量对象上随机打开/关闭(问题涉及过程、函数、触发器和视图…)

由于使用过滤索引和查询通知等功能需要启用QUOTED_IDENTIFIER,因此我想找到一种方法来查找所有关闭的索引并启用它

在这个网站上研究这个问题时,我发现了这篇(以及其他一些)文章,但我发现没有一篇文章能够在不重新生成所有SQL脚本(我实际上有数千个需要修复的对象)或编写C#代码的情况下很好地解决这个问题

所以我开发了一种基于SQL的处理方法。这将重新编译所有进程,并生成由于某种原因无法编译的任何进程的列表。我知道这不能处理不同的模式(dbo与sales与其他模式),但您可以根据需要对此进行调整。在我的情况下,我不需要担心这个

    SET NOCOUNT ON

    -- MAKE SURE THIS IS ON!!
    SET QUOTED_IDENTIFIER ON

    --- Used in try/catch below
    DECLARE @ErrorMessage nvarchar(4000);
    DECLARE @ErrorSeverity int;
    DECLARE @ErrorState int;

    DECLARE @name sysname
    DECLARE @type char(2)
    DECLARE @objType nvarchar(50)
    DECLARE @createCommand nvarchar(max)
    DECLARE @dropCommand nvarchar(max)
    DECLARE @success bit

    IF OBJECT_ID(N'tempdb..#ProcList', N'U') IS NOT NULL DROP TABLE #ProcList

    CREATE TABLE #ProcList
    (
        name            sysname         NOT NULL PRIMARY KEY,
        id              int             NOT NULL,
        type            char(2)         NOT NULL,
        definition      nvarchar(max)   NULL,
        alterstmt       nvarchar(max)   NULL,
        processed       bit             NOT NULL,
        successful      bit             NOT NULL
    )

    --- Build the list of objects that have quoted_identifier off
    INSERT INTO #ProcList
    SELECT 
        so.name, 
        so.object_id, 
        so.type, 
        sm.definition, 
        NULL, 
        0, 
        0
    FROM sys.objects so
        INNER JOIN sys.sql_modules sm
            ON so.object_id = sm.object_id
    WHERE 
        LEFT(so.name, 3) NOT IN ('sp_', 'xp_', 'ms_')
        AND sm.uses_quoted_identifier = 0
    ORDER BY 
        name

    -- Get the first object
    SELECT @name = MIN(name) FROM #ProcList WHERE processed = 0

    --- As long as we have one, keep going
    WHILE (@name IS NOT NULL)
    BEGIN

        SELECT
            @createCommand = definition,
            @type = type
        FROM #ProcList 
        WHERE name = @name

        --- Determine what type of object it is
        SET @objType = CASE @type
                WHEN 'P'  THEN 'PROCEDURE' 
                WHEN 'TF' THEN 'FUNCTION'
                WHEN 'IF' THEN 'FUNCTION'
                WHEN 'FN' THEN 'FUNCTION'
                WHEN 'V'  THEN 'VIEW'
                WHEN 'TR' THEN 'TRIGGER'
            END

        --- Create the drop command
        SET @dropCommand = 'DROP ' + @objType + ' ' + @name

        --- record the drop statement that we are going to execute
        UPDATE #ProcList 
        SET 
            processed = 1, 
            alterstmt = @dropCommand 
        WHERE name = @name

        --- Assume we will not succeed
        SET @success = 0

        BEGIN TRANSACTION

        --- Drop the current proc
        EXEC sp_executesql @dropCommand

        BEGIN TRY

            --- Execute the create statement from the definition
            EXEC sp_executesql @createCommand

            --- If we reached this point, it all worked
            SET @success = 1

            COMMIT

        END TRY
        BEGIN CATCH

            --- oops something went wrong
            SELECT
                @ErrorMessage = ERROR_MESSAGE(),
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE();

            PRINT 'Error processing ' + @name
            RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @name)

            --- Undo the transaction, which undoes the drop above
            ROLLBACK

        END CATCH

        --- At this point, there should be no open transactions
        IF @@TRANCOUNT > 0 
        BEGIN
            PRINT 'ERROR... transaction count not right!!'
            ROLLBACK
            RETURN
        END

        --- check to make sure the object still exists after executing the alter statement, and that we didn't detect an earlier error
        --- If it's all good, then mark the proc as having been successful
        IF (
            @success = 1
            AND EXISTS (
                SELECT name 
                FROM sys.objects so 
                    INNER JOIN sys.sql_modules sm 
                        ON so.object_id = sm.object_id 
                WHERE name = @name
            )
        )
        BEGIN
            UPDATE #ProcList SET successful = 1 WHERE name = @name
        END      

        -- Get the next one... if none are left the result will be NULL
        SELECT @name = MIN(name) FROM #ProcList where processed = 0

    END

    -- What wasn't successful??
    SELECT * 
    FROM #ProcList 
    WHERE successful = 0 
    ORDER BY name 

我已经更改了@Earl编写的脚本(见上文),以便它能够为SQL Server 2016及更高版本创建或更改模式,并与模式一起工作

它仍然不是完美的,因为找到“创建”部分并不简单


你的剧本帮助了我们。非常感谢。@Earl;非常感谢你。
set nocount ON

    -- MAKE SURE THIS IS ON!!
    SET QUOTED_IDENTIFIER ON

    DROP TABLE if exists #ProcList

    CREATE TABLE #ProcList
    (
        name            sysname         NOT NULL /*PRIMARY KEY*/,
        SchemaName      sysname         not null,
        id              int             NOT NULL,
        type            char(2)         NOT NULL,
        definition      nvarchar(max)   NULL,
        alterstmt       nvarchar(max)   NULL,
        processed       bit             NOT NULL,
        successful      bit             NOT null,
        primary key clustered (SchemaName, name)
    )


    --- Build the list of objects that have quoted_identifier off
    INSERT INTO #ProcList
    SELECT 
        so.name, 
        schema_name(so.schema_id),
        so.object_id, 
        so.type, 
        sm.definition, 
        NULL, 
        0, 
        0
    FROM sys.objects so
        INNER JOIN sys.sql_modules sm
            ON so.object_id = sm.object_id
    WHERE 
        LEFT(so.name, 3) NOT IN ('sp_', 'xp_', 'ms_')
        AND sm.uses_quoted_identifier = 0
    ORDER BY 
        so.name

    --- Used in try/catch below
    DECLARE @ErrorMessage nvarchar(4000);
    DECLARE @ErrorSeverity int;
    DECLARE @ErrorState int;

    DECLARE @name sysname, @SchemaName sysname 
    declare @type char(2)
    DECLARE @objType nvarchar(50)
    DECLARE @createCommand nvarchar(max)
    DECLARE @dropCommand nvarchar(max)
    DECLARE @success bit

    -- Get the first object
    SELECT top (1) @name = name, @SchemaName= SchemaName FROM #ProcList WHERE processed = 0 order by SchemaName, name

    --- As long as we have one, keep going
    WHILE (@name IS NOT NULL)
    BEGIN
        raiserror ('at %s %s', 10, 1, @SchemaName, @name) with nowait
        SELECT
            @createCommand = definition,
            @type = type
        FROM #ProcList 
        WHERE name = @name

        --- Determine what type of object it is
        SET @objType = CASE @type
                WHEN 'P'  THEN 'PROCEDURE' 
                WHEN 'TF' THEN 'FUNCTION'
                WHEN 'IF' THEN 'FUNCTION'
                WHEN 'FN' THEN 'FUNCTION'
                WHEN 'V'  THEN 'VIEW'
                WHEN 'TR' THEN 'TRIGGER'
            END

        --- Create the drop command
        SET @dropCommand = 'DROP ' + @objType + ' ' + quotename(@SchemaName) + '.' + quotename(@name)

        --- record the drop statement that we are going to execute
        UPDATE #ProcList 
        SET 
            processed = 1, 
            alterstmt = @dropCommand 
        WHERE name = @name and SchemaName = @SchemaName

        --- Assume we will not succeed
        SET @success = 0

        BEGIN TRANSACTION

        --- Drop the current proc
        --EXEC sp_executesql @dropCommand

        BEGIN TRY

            set @createCommand = replace(@createCommand, 'Create proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create  proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create   proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create    proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create     proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create' + char(13) + char(10) + 'proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create' + char(10) + 'proc', 'Create or Alter Proc')
            set @createCommand = replace(@createCommand, 'Create view', 'Create or Alter view')
            set @createCommand = replace(@createCommand, 'Create  view', 'Create or Alter view')
            set @createCommand = replace(@createCommand, 'Create   view', 'Create or Alter view')
            set @createCommand = replace(@createCommand, 'Create    view', 'Create or Alter view')
            --- Execute the create statement from the definition
            EXEC sp_executesql @createCommand

            --- If we reached this point, it all worked
            SET @success = 1

            COMMIT

        END TRY
        BEGIN CATCH

            --- oops something went wrong
            SELECT
                @ErrorMessage = ERROR_MESSAGE(),
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE();

            PRINT 'Error processing ' + @name
            exec dbo.LongPrint  @createCommand
            
            RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @name)

            --- Undo the transaction, which undoes the drop above
            ROLLBACK

        END CATCH

        --- At this point, there should be no open transactions
        IF @@TRANCOUNT > 0 
        BEGIN
            PRINT 'ERROR... transaction count not right!!'
            ROLLBACK
            RETURN
        END

        --- check to make sure the object still exists after executing the alter statement, and that we didn't detect an earlier error
        --- If it's all good, then mark the proc as having been successful
        IF (
            @success = 1
            AND EXISTS (
                SELECT so.name 
                FROM sys.objects so 
                    INNER JOIN sys.sql_modules sm 
                        ON so.object_id = sm.object_id 
                WHERE so.name = @name and schema_name(so.schema_id) = @SchemaName
            )
        )
        BEGIN
            UPDATE #ProcList SET successful = 1 WHERE name = @name and SchemaName = @SchemaName
        END      

        SELECT @name = null
        -- Get the next one... if none are left the @name will be NULL
        SELECT top (1) @name = name, @SchemaName= SchemaName FROM #ProcList WHERE processed = 0 order by SchemaName, name
    END

    -- What wasn't successful??
    SELECT * 
    FROM #ProcList 
    WHERE successful = 0 
    ORDER BY SchemaName, name