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