[英]Changing Quoted_Identifier on existing Constraints / Rules / Procedures
我目前正在使用 2008-r2 服務器上的舊式數據庫,該數據庫使用了許多在 Quoted Identifier 設置為 off 的情況下創建的對象。
我主要看這些類型:
CHECK_CONSTRAINT
DEFAULT_CONSTRAINT
RULE
SQL_SCALAR_FUNCTION
SQL_STORED_PROCEDURE
SQL_TRIGGER
VIEW
我現在正在嘗試更改引用標識符設置,因為我發現我什至無法更改約束,這讓我立即感到困惑。
對於約束:我想我必須以某種方式制作臨時克隆/副本,刪除原始副本,然后使用副本和 Quoted_Identifier 設置為 ON 重新創建它們,但我真的不知道如何執行此操作或如何執行此操作自動執行此操作,因為我的 SQL 技能有限。 有人可以幫助我嗎? 或者有人知道更簡單的替代方法嗎?
我在安裝過程中遇到了一個錯誤,導致 QUOTED_IDENTIFIER 在大量對象上隨機打開/關閉(問題涉及過程、函數、觸發器和視圖......)。
由於使用過濾索引和查詢通知之類的東西需要 QUOTED_IDENTIFIER ON,我想要一種方法來找到它關閉的所有內容並將其打開。
在研究這個站點上的問題時,我發現了這個(以及其他一些)帖子,但我發現沒有一個可以在不重新生成所有 SQL 腳本的情況下做到這一點的好方法(我確實有數千個需要修復的對象)或編寫 C# 代碼。
所以我開發了一種基於 SQL 的處理方式。 這將重新編譯所有 proc,並生成一個列表,列出由於某種原因無法編譯的任何程序。 我知道這不能處理不同的模式(dbo vs. sales vs.whatever),但您可以根據需要對其進行調整。 在我的情況下,我不需要擔心。
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
編寫此數據庫的腳本,刪除所有 Quoted_Identifier OFF,從腳本重新創建數據庫並重新導入數據(該向導包含在 MS SS 中)。
這種解決方案可能有很多風味。 使用動態 sql /smo 技術解決的類似問題: 更改數據庫中所有存儲過程的 ANSI_NULLS 設置
我已經更改了@Earl 編寫的腳本(見上文),以便它執行 CREATE OR ALTER,並且也適用於 SQL Server 2016 及更高版本的模式。
它仍然不完美,因為找到“CREATE”部分並不簡單。
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.