Обновление ВСЕХ триггеров с помощью "НЕ ДЛЯ РЕПЛИКАЦИИ" в SQL Server 2012
У нас есть 505 триггеров, которые нуждаются в NOT FOR REPLICATION
флаг установлен. Найден запрос пользователя, который ищет "%AS%" и добавляет NOT FOR REPLICATION
как раз перед этим
Проблема в том, что он попадает в 1-й экземпляр AS, который может быть комментарием (т.е. -- Trigger to prevent update of LastUpdated column
) или имя триггера (т.е. trgLastUpdated
).
Ниже то, что мы пытались. У кого-нибудь есть предложения по поиску правильных AS
и как разместить NOT FOR REPLICATION
как раз перед этим?
Основной запрос:
DROP TABLE #TriggersNFR
CREATE TABLE #TriggersNFR (ServerName varchar(250), Dbname varchar(250),TableName varchar(250), TriggerName varchar(250), FixingScript varchar(max))
exec sp_MSforeachdb '
IF ''?'' NOT IN (''tempdb'',''master'',''model'',''msdb'') BEGIN
USE ?
insert into #TriggersNFR
SELECT @@servername,''?'' DBName,OBJECT_NAME(parent_object_id) TableName,
OBJECT_NAME(o.object_id) [Trigger Name],
STUFF (REPLACE(definition,''CREATE TRIGGER'',''ALTER TRIGGER''),
PATINDEX(''%AS%'',REPLACE(definition,''CREATE TRIGGER'',''ALTER TRIGGER'')),0,''
NOT FOR REPLICATION '')
+ ''
GO
''
from ?.sys.objects o
join ?.sys.sql_modules m
on o.object_id = m.object_id
where o.type = ''TR''
and OBJECTPROPERTY(o.object_id, ''ExecIsTriggerNotForRepl'') = 0
AND OBJECTPROPERTY(o.object_id, ''IsMSShipped'') = 0
END
'
select * from #TriggersNFR
order by Dbname
который имеет пример вывода в столбце FixingScript:
-- =============================================
-- Author: #####
-- Create date: 9/14/2012
-- Description: Prevents updating of a L
NOT FOR REPLICATION astUpdated date that would cause app to drop an update when the next one comes along.
-- =============================================
ALTER TRIGGER trgAppUpdates_Upd_LastUpdated
ON APP_REGISTER_UPDATES
AFTER UPDATE
AS
BEGIN
Попытался изменить это с неудачными результатами:
PATINDEX(''%AS%'',
в
PATINDEX(char(13)+''%AS%''
или же
PATINDEX(''%''+char(13)+''AS%''
или же
PATINDEX(''%''+char(13)+char(10)+''AS%''
3 ответа
Ты пробовал ''% AS%''
(пробел перед КАК)?
Вы пробовали поиск с учетом регистра?PATINDEX(''%AS%'', [skipped], COLLATE SQL_Latin1_General_Cp1_CS_AS)
или любой другой случай сопоставления?
Кстати, МНОГО спасибо за сценарий:).
В моем коде я использую "case" вместо PATINDEX
select
'
----------------------------------------------------
----------------------------------------------------
----------------------------------------------------
DROP TRIGGER [dbo].[' + name + ']
GO
----------------------------------------------------
' +
SUBSTRING([definition], 1, FirstAsPosition) + ' NOT FOR REPLICATION ' +
SUBSTRING([definition], FirstAsPosition, len([definition]))
+ '
GO
----------------------------------------------------
'
AS SQLTriggersScript
from
(
select
name,[definition],
case when
(case when AsIndex1 = 0 then 1000000 else AsIndex1 end)
<
(case when AsIndex2 = 0 then 1000000 else AsIndex2 end)
then
AsIndex1
else
AsIndex2
end AS FirstAsPosition
from
(
select
obj.name, [definition],
CHARINDEX(' AS', [definition]) as AsIndex1,
CHARINDEX(CHAR(13)+CHAR(10)+'AS', [definition]) as AsIndex2
from sys.sql_modules m
inner join sys.objects obj on obj.object_id=m.object_id
where obj.type ='TR'
AND OBJECTPROPERTY(obj.object_id, 'ExecIsTriggerNotForRepl') = 0
AND OBJECTPROPERTY(obj.object_id, 'IsMSShipped') = 0
) as t
) as t
Я предлагаю решение с использованием объектов управления SQL Server (SMO):
// compile with:
// /r:Microsoft.SqlServer.Smo.dll
// /r:Microsoft.SqlServer.ConnectionInfo.dll
// /r:Microsoft.SqlServer.Management.Sdk.Sfc.dll
// using System;
// using Microsoft.SqlServer.Management.Smo;
// using Microsoft.SqlServer.Management.Common;
void M(){
string sqlServerLogin ="__" ;
string password = "__";
string remoteSvrName ="__" ;
string dbName = "__";
ServerConnection conn = new ServerConnection(remoteSvrName);
conn.LoginSecure = false;
conn.Login = sqlServerLogin;
conn.Password = password;
Server srv = new Server(conn);
var db = srv.Databases[dbName];
foreach (Table tab in db.Tables)
{
foreach (Trigger trig in tab.Triggers)
{
trig.TextMode = false;
trig.NotForReplication = true;
trig.TextMode = true;
trig.Alter();
Console.WriteLine(trig.Name);
}
}
}