If you use SSMS (or other similar tool) to run the code produced by this script, you will get exactly the same error. It could run all right when you inserted batch delimiters (GO), but now that you don’t, you’ll face the same issue in SSMS too.
On the other hand, the reason why you cannot put GO in your dynamic scripts is because GO isn’t a SQL statement, it’s merely a delimiter recognised by SSMS and some other tools. Probably you are already aware of that.
Anyway, the point of GO is for the tool to know that the code should be split and its parts run separately. And that, separately, is what you should do in your code as well.
So, you have these options:
-
insert
EXEC sp_execute @sqljust after the part that drops the trigger, then reset the value of@sqlto then store and run the definition part in its turn; -
use two variables,
@sql1and@sql2, store the IF EXISTS/DROP part into@sql1, the CREATE TRIGGER one into@sql2, then run both scripts (again, separately).
But then, as you’ve already found out, you’ll face another issue: you cannot create a trigger in another database without running the statement in the context of that database.
Now, there are 2 ways of providing the necessary context:
1) use a USE statement;
2) run the statement(s) as a dynamic query using EXEC targetdatabase..sp_executesql N'…'.
Obviously, the first option isn’t going to work here: we cannot add USE … before CREATE TRIGGER, because the latter must be the only statement in the batch.
The second option can be used, but it will require an additional layer of dynamicity (not sure if it’s a word). It’s because the database name is a parameter here and so we need to run EXEC targetdatabase..sp_executesql N'…' as a dynamic script, and since the actual script to run is itself supposed to be a dynamic script, it, therefore, will be nested twice.
So, before the (second) EXEC sp_executesql @sql; line add the following:
SET @sql = N'EXEC ' + @dbname + '..sp_executesql N'''
+ REPLACE(@sql, '''', '''''') + '''';
As you can see, to integrate the contents of @sql as a nested dynamic script properly, they must be enclosed in single quotes. For the same reason, every single quotation mark in @sql must be doubled (e.g. using the REPLACE() function, as in the above statement).
Ok … I’m struggling to find a way to do this without having an exec wrapped around an exec. The code is already ugly enough having this in dynamic, but until I change the way I sync all my admin db’s, this is my best bet. Modified a known process out there slightly to capture DDL events, and I need to push the trigger to all databases.
1) Why can you not check for trigger existance with OBJECT_ID? Look how I had to find it, not how I would normally do it.
2) Without dropping/recreating the object every time, how can I use a database and create an object?
Thanks in advance
SET NOCOUNT ON
-- Setup DDLChangeLog Table
IF OBJECT_ID('DDLChangeLog','U') IS NULL
BEGIN
CREATE TABLE [dbo].[DDLChangeLog]
(
[LogId]INTIDENTITY(1,1) CONSTRAINT PK_DDLChangeLog PRIMARY KEY CLUSTERED
,[DatabaseName] VARCHAR(256)
,[EventType]VARCHAR(50)
,[ObjectName]VARCHAR(256)
,[ObjectType]VARCHAR(25)
,[SqlCommand]VARCHAR(MAX)
,[EventDate]DATETIME CONSTRAINT [DF_EventsLog_EventDate] DEFAULT (GETDATE())
,[LoginName]VARCHAR(256)
,[ProgramName]VARCHAR(256)
)
GRANT INSERT ON [dbo].[DDLChangeLog] TO [public]
END
-- Push Trigger to all databases
IF OBJECT_ID('tempdb.dbo.#systriggers') IS NOT NULL
DROP TABLE #systriggers
SELECT TOP 0 * INTO #systriggers FROM [sys].[triggers]
DECLARE
@DBNameSYSNAME
,@LoggingDBNameSYSNAME
SET @LoggingDBName = 'admin'
DECLARE #dbs CURSOR STATIC LOCAL FOR
SELECT [name] FROM [master].[sys].[databases]
WHERE [source_database_id] IS NULL
AND [name] != 'tempdb'
AND [name] = 'admin'
ORDER BY [name]
OPEN #dbs
FETCH NEXT FROM #dbs INTO @DBName
WHILE @@FETCH_STATUS = 0
BEGIN
-- Lame way of checking to see if trigger exists as OBJECT_ID does not work for triggers
TRUNCATE TABLE #systriggers
INSERT INTO #systriggers
EXEC('USE [' + @DBName + '] SELECT * FROM [sys].[triggers]')
IF NOT EXISTS(SELECT * FROM #systriggers WHERE [parent_class_desc] = 'DATABASE' AND [name] = N'DDLChange_trg')
BEGIN
EXEC('
USE [' + @DBName + ']
GO
/*******************************************************************************************************
**Name:dbo.DDLChange_trg
**Desc:Trigger to capture all database DDL events
**Auth:Adam Bean (SQLSlayer.com)
Modified from: http://www.sqlteam.com/article/using-ddl-triggers-in-sql-server-2005-to-capture-schema-changes
**Date:2008.09.24
*******************************************************************************
**Change History
*******************************************************************************
**Date:Author:Description:
**-------------------------------------------------------
********************************************************************************************************/
CREATE TRIGGER [DDLChange_trg] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
SET NOCOUNT ON
DECLARE
@dataXML
,@ProgramNameVARCHAR(256)
SELECT @ProgramName = [program_name] FROM [sys].[dm_exec_sessions] WHERE [session_id] = @@SPID
SET @data = EVENTDATA()
INSERT INTO [' + @LoggingDBName + '].[dbo].[DDLChangeLog]
([DatabaseName], [EventType], [ObjectName], [ObjectType], [SqlCommand], [LoginName], [ProgramName])
VALUES
(
@data.value(''(/EVENT_INSTANCE/DatabaseName)[1]'', ''VARCHAR(256)'')
,@Data.value(''(/EVENT_INSTANCE/EventType)[1]'', ''VARCHAR(50)'')
,@Data.value(''(/EVENT_INSTANCE/ObjectName)[1]'', ''VARCHAR(256)'')
,@Data.value(''(/EVENT_INSTANCE/ObjectType)[1]'', ''VARCHAR(25)'')
,@Data.value(''(/EVENT_INSTANCE/TSQLCommand)[1]'', ''VARCHAR(MAX)'')
,@Data.value(''(/EVENT_INSTANCE/LoginName)[1]'', ''VARCHAR(256)'')
,@ProgramName
)
SET NOCOUNT OFF
')
END
ELSE
PRINT 'Trigger already exists in database: ' + @DBName + ''
FETCH NEXT FROM #dbs INTO @DBName
END
CLOSE #dbs
DEALLOCATE #dbs
SET NOCOUNT OFF
Problem
When you’re executing a CREATE/ALTER statement to create a procedure/view/function/trigger, you get one of the following errors:
‘CREATE/ALTER PROCEDURE’ must be the first statement in a query batch
‘CREATE VIEW’ must be the first statement in a query batch.
‘CREATE FUNCTION’ must be the first statement in a query batch.
‘CREATE TRIGGER’ must be the first statement in a query batch.
You can’t execute these CREATE/ALTER statements with other statements.
Solution
The solution is to execute the CREATE/ALTER statement separately from other statements. How you do that depends on if you’re using SSMS/sqlcmd/osql or executing from C#.
If you’re executing from SSMS (or sqlcmd/osql)
Add the keyword GO right before CREATE statement. This is the default batch separator in SSMS. It splits the query into multiple batches. In other words, it executes the CREATE statement by itself in its own batch, therefore solving the problem of it needing to be the first statement in a batch. Here’s an example:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'spGetAllPosts') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].spGetAllPosts
GO
CREATE PROCEDURE [dbo].spGetAllPosts
AS
BEGIN
SELECT * FROM Posts
END
Code language: SQL (Structured Query Language) (sql)
If you’re executing from C#
You can’t use the GO keyword in C#. Instead you have to execute the SQL queries separately. The best way to do that is to execute the first part, then change the CommandText and execute the second part.
using System.Data.SqlClient;
string dropProcQuery =
@"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'spGetAllPosts') AND type in (N'P', N'PC'))
DROP PROCEDURE[dbo].spGetAllPosts";
string createProcQuery =
@"CREATE PROCEDURE [dbo].spGetAllPosts
AS
BEGIN
SELECT * FROM Posts
END";
using (var con = new SqlConnection(ConnectionString))
{
using (var cmd = new SqlCommand(dropProcQuery, con))
{
//Execute the first statement
con.Open();
cmd.ExecuteNonQuery();
//Then execute the CREATE statement
cmd.CommandText = createProcQuery;
cmd.ExecuteNonQuery();
}
}
Code language: C# (cs)
Related Articles
|
|
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
08.06.2017, 23:55. Показов 4425. Ответов 42 Ребята помогите. Есть вторая таблица (основная) Есть исходная таблица в excel, которая будет подливаться в sql server Вопрос в следующем: Потом просто будет через join это всё вытягиваться и таблица будет уже полностью как нужно заполнена. Добавлено через 7 часов 6 минут
0 |
|
IT_Exp Эксперт 34794 / 4073 / 2104 Регистрация: 17.06.2006 Сообщений: 32,602 Блог |
08.06.2017, 23:55 |
|
Ответы с готовыми решениями: Импорт в БД SQL Server CE Возникла надобность импортировать данные в .sdf файл из Excel, проверяя на лету различные условия, например:… Импорт из Excel в SQL Сообщения Импорт из xml в MS SQL 42 |
|
qwertehok 5638 / 4482 / 1087 Регистрация: 29.08.2013 Сообщений: 27,958 Записей в блоге: 3 |
||||
|
12.06.2017, 16:18 |
||||
|
1. сначала запросом
импортируй данные во временную таблицу 2. далее проверка (правильно ли заполнены, если значения и другое)
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
12.06.2017, 17:17 [ТС] |
|
|
кстати, можно к примеру без вьюшки триггером сугубо преобразовывать? это так ради интереса.
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
12.06.2017, 17:32 |
|
|
при вставке чего и в какую таблицу? А если сделать такой же INSTEAD OF INSERT триггер, то нормальные записи в неё и не записывать, а писать сразу в реальные таблицы. А в неё можно записывать только проблемные.
0 |
|
Shamann87 0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
||||
|
13.06.2017, 16:32 [ТС] |
||||
|
ФИО. ГОРОД. ТОВАР. ГРУЗЧИК. ДАТА это одна структура таблицы в которую будет импортироваться информация с текстовыми столбцами ФИО. iD_ГОРОД. iD_ТОВАР. iD_ГРУЗЧИК. ДАТА. это структура таблицы которая уже должна быть после отработки триггера с iD вместо данных. Добавлено через 22 часа 47 минут Сообщение от YuryK как-то так: вот структура.
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
13.06.2017, 16:39 |
|
|
Сообщение от Shamann87 CREATE TABLE ТАБЛИЦА ДЛЯ ИМПОРТА и такой скрипт, по вашему, сработает? Сообщение от YuryK Если в промежуточную, с текстовыми полями ГОРОД, ТОВАР, ГРУЗЧИК, как во вьюшке, то да. а у вас Id-ы, а не текстовые поля. У вас боевая таблица будет с Id-ами, а для импорта нужна с текстовами полями. Или ТАБЛИЦА ДЛЯ ИМПОРТА — это она и есть? Тогда где скрипт таблицы для импорта?
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
13.06.2017, 16:44 [ТС] |
|
|
Сообщение от YuryK ТАБЛИЦА ДЛЯ ИМПОРТА таблица для импорта это уже боевая, я её просто так обозначил, в ней должны уже записываться ID-шки, которые я потом через inner join буду вязать со словарями и выгружать структурированную информацию.
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
13.06.2017, 16:50 |
|
|
Сообщение от Shamann87 я создавала промежуточную таблицу, но дело в том что мне заливало те поля что не подвязаны к словарям нормально, те что подвязаны, заливало пустые столбцы и где её скрипт и скрип триггера? Сообщение от Shamann87 ID_ТОВАРА INT DEFAULT ‘ ‘, странное DEFAULT для целочисленного поля
0 |
|
Shamann87 0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
||||
|
13.06.2017, 17:08 [ТС] |
||||
|
Сообщение от YuryK и где её скрипт и скрип триггера?
импортировал данные не кодом а через импорт.
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
13.06.2017, 17:25 |
|
|
Сообщение от Shamann87 импортировал данные не кодом а через импорт. главное не как, а куда. Если во вьюшку, то там вставка не в ту таблицу у вас записана. Вы сначала определитесь с объектами БД, какие оставите, а какие уберете, прежде чем «код привязывать»
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
13.06.2017, 23:50 [ТС] |
|
|
Можно ли повесить триггер на ТАБЛИЦА ДЛЯ ИМПОРТА боевую таблицу, чтобы когда я в неё импортировал он на входе заменял текстовые значения на id-ки?
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
14.06.2017, 00:00 |
|
|
Сообщение от Shamann87 на ТАБЛИЦА ДЛЯ ИМПОРТА боевую таблицу я не понял смысла в этом словосочетании в боевую таблицу [ТАБЛИЦА ДЛЯ ИМПОРТА] вы не можете вставлять текстовые значения в поля ID_ГОРОДА, ID_ТОВАРА и ID_ГРУЗЧИКА, т.к. там ожидаются числа. Для этого и нужна промежуточная таблица ИМПОРТ (или представление v_ИМПОРТ) у которых такие (текстовые) поля есть. Но в триггере этих таблиц вы будете вставлять уже в таблицу [ТАБЛИЦА ДЛЯ ИМПОРТА], подобрав в справочных таблицах нужные Id-ы.
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
14.06.2017, 17:15 [ТС] |
|
|
Сообщение от YuryK триггере может ли триггер не отрабатывать, хотя он и создается, но подчёркнут и пишет инструкция CREATE TRIGGER должна быть единственной в пакете?
0 |
|
YuryK 1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
||||
|
14.06.2017, 17:41 |
||||
|
это момент создания триггера, а не отрабатывания.
перед и после оператора создания триггера
0 |
|
Shamann87 0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
||||
|
14.06.2017, 17:41 [ТС] |
||||
|
Сообщение от YuryK ИМПОРТ такой код должен быть если не делать вьюшку, а импортировать данные в таблицу ИМПОРТ?
0 |
|
YuryK 1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
||||
|
14.06.2017, 17:47 |
||||
|
нет В какой таблице какие поля уж запомнить пора
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
15.06.2017, 14:52 [ТС] |
|
|
0 |
|
1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
|
|
15.06.2017, 16:46 |
|
|
Сообщение от Shamann87 так и через мастер импорта? а это что за зверь? Если он куда-то умеет заносить, пусть и заносит в таблицу ИМПОРТ.
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
15.06.2017, 17:08 [ТС] |
|
|
[quote=»YuryK;10546945″]а это что за зверь?
0 |
|
0 / 0 / 0 Регистрация: 08.06.2017 Сообщений: 31 |
|
|
16.06.2017, 17:36 [ТС] |
|
|
Сообщение от YuryK а это что за зверь? не знаете как обойти это? Добавлено через 10 минут Сообщение от Shamann87 а это что за зверь? я даже создавал такую же таблицу в которую импортировал а потом через insert переносил данные в таблицу на которую сделан триггер, всё равно не отрабатывает, даже не вставляет инфо, отключаю триггер, инфо переносится.
0 |
|
YuryK 1040 / 856 / 335 Регистрация: 08.12.2016 Сообщений: 3,283 |
||||
|
16.06.2017, 17:45 |
||||
|
Сообщение от Shamann87 а потом через insert переносил данные в таблицу на которую сделан триггер, всё равно не отрабатывает, даже не вставляет инфо, отключаю триггер, инфо переносится не верю. значит или триггер не верный или данные не подходят. Сообщение от Shamann87 даже не вставляет инфо ну так триггер на это и заточен.
0 |
|
BasicMan Эксперт 29316 / 5623 / 2384 Регистрация: 17.02.2009 Сообщений: 30,364 Блог |
16.06.2017, 17:45 |
|
Помогаю со студенческими работами здесь Импорт db data_dump.sql Импорт SQL в Access? импорт из SQL Server Импорт sql в posgresql Импорт sql в phpmyadmin Искать еще темы с ответами Или воспользуйтесь поиском по форуму: 40 |
|
Новые блоги и статьи
Все статьи Все блоги / |
||||
|
Микросервис на Python с FastAPI и Docker
ArchitectMsa 23.04.2025 В эпоху облачных вычислений и растущей сложности программных продуктов классическая монолитная архитектура всё чаще уступает место новым подходам. Микросервисная архитектура становится фаворитом. . . |
Создаем веб-приложение на Vue.js и Laravel
Reangularity 23.04.2025 Выбор правильного технологического стека определяет успех веб-проекта. Laravel и Vue. js формируют отличную комбинацию для создания современных приложений. Laravel — это PHP-фреймворк с элегантным. . . |
Максимальная производительность C#: Span<T> и Memory<T>
stackOverflow 22.04.2025 Мир высоконагруженных приложений безжалостен к неэффективному коду. Каждая миллисекунда на счету, каждый выделенный байт памяти может стать причиной падения производительности. Разработчики на C#. . . |
JWT аутентификация в Java
Javaican 21.04.2025 JWT (JSON Web Token) представляет собой открытый стандарт (RFC 7519), который определяет компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Эта информация. . . |
Спринты Agile: Планирование, выполнение, ревью и ретроспектива
EggHead 21.04.2025 Спринты — сердцевина Agile-методологии, позволяющая командам создавать работающий продукт итерационно, с постоянной проверкой гипотез и адаптацией к изменениям. В основе концепции спринтов лежит. . . |
|
Очередные открытия мега простых чисел, сделанные добровольцами с помощью домашних компьютеров
Programma_Boinc 21.04.2025 Очередные открытия мега простых чисел, сделанные добровольцами с помощью домашних компьютеров. 3 марта 2025 года, в результате обобщенного поиска простых чисел Ферма в PrimeGrid был найден. . . |
Система статов в Unity
GameUnited 20.04.2025 Статы — фундаментальный элемент игрового дизайна, который определяет характеристики персонажей, предметов и других объектов в игровом мире. Будь то показатель силы в RPG, скорость передвижения в. . . |
Статические свойства и методы в TypeScript
run.dev 20.04.2025 TypeScript прочно занял своё место в системе современной веб-разработки. Этот строго типизированный язык программирования не просто расширяет возможности JavaScript — он делает разработку более. . . |
Batch Transform и Batch Gizmo Drawing API в Unity
GameUnited 20.04.2025 В мире разработки игр и приложений на Unity производительность всегда была критическим фактором успеха. Создатели игр постоянно балансируют между визуальной привлекательностью и плавностью работы. . . |
Звук в Unity: Рандомизация с Audio Random Container
GameUnited 20.04.2025 В современных играх звуковое оформление часто становится элементом, который либо полностью погружает игрока в виртуальный мир, либо разрушает атмосферу за считанные минуты. Представьте: вы исследуете. . . |
Наверх
You just need to change the command delimiter that the client is looking for in order to split commands:
delimiter $$
CREATE TRIGGER new_trx_tmp_on_transaction_update AFTER UPDATE ON transaction
FOR EACH ROW
BEGIN
IF NEW.trx_status = 1 AND ( NEW.cat_id = 'CASHBACK' || NEW.cat_id = 'REFUND') THEN
INSERT INTO trx_tmp( `id`, `trx_id`, `user_id`, `trx_merchant_trxid`, `trx_amount`, `amount_left`, `cat_id`, `created_at`, `updated_at` ) VALUES ( NULL, NEW.id, NEW.userid, NEW.trx_merchant_trxid, NEW.trx_amount, NEW.trx_amount, NEW.cat_id, NOW(), NOW() );
END IF;
END
$$
The default is a semi-colon, hence it complaining at the end of the INSERT line when you try and create your trigger.
It’s all explained in the documentation here.
