DDL statements against deleted inserted in DML trigger - sql

I am trying to find impact of doing DDL statement against deleted and inserted logical tables inside table trigger. I have:
CREATE TRIGGER [Trigger52]
ON [dbo].[Table1]
FOR DELETE, INSERT, UPDATE
AS
BEGIN
create table inserted (c1 int)
select * from inserted
END
When it is triggered, I expected to get an error. Instead, it seems to ignore create table statement entirely and select rows that have been inserted.
Is there a documentation describing this behavior or explanation?

Inside triggers there are always two pseudo-tables existing: inserted and deleted. See Using the inserted and deleted Tables:
SQL Server automatically creates and
manages these tables. You can use
these temporary, memory-resident
tables to test the effects of certain
data modifications and to set
conditions for DML trigger actions.
You cannot directly modify the data in
the tables or perform data definition
language (DDL) operations on the
tables.

Related

one sql trigger insert,update,delete for all tables in the database

is it possible to declare one Sql Trigger Insert, Update, Delete for all tables in the database instead of creating a separate trigger for each table? I just want a simple history of what actions have been taken e.g. TABLE A deletes a row ,TABLE B updates a row ,TABLE C Add new row .. and the trigger will insert a new row to another table with that information I want.
No, a trigger can only be defined on a specified table.
You should read up on the auditing features of SQL Server (http://technet.microsoft.com/en-us/library/cc280386.aspx). They are more performant and more flexible in what you want to achieve. Unfortunately they are not available in the Express Edition.

SQL use temporary tables in trigger

I have a trigger in MSSQL Server 2008R2 :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_HosFile_Delete]
ON [dbo].[hosfile] FOR DELETE
AS
insert into #pys(pyGuid)
SELECT EntryGuid AS pyGuid FROM er000 AS er
insert into t2(C1) select pyGuid from #pys
After the trigger has executed the t2 table is empty. Why is it empty?
If I execute the query above without a trigger the t2 table is filled.
is there any problem with using a temporary table in a trigger?
Damien's answer is correct: you can use temporary tables in triggers, but it is strongly recommended to define them there, since the trigger can fire in various contexts.
If you use temporary tables in triggers, check for temporary table existence as you do not control the context and it might be already there:
IF OBJECT_ID('tempdb..#pys') IS NOT NULL
DROP TABLE #pys
Also, temporary tables can be created on the fly:
SELECT * INTO #tmp
FROM inserted
This is particularly useful when trigger contains dynamic SQL that needs to access inserted or deleted special tables which are not visible in the dynamic SQL scope.
Avoid using ##tmp (global temporary variables), as these are globally visible and can lead to trouble when multiple SPIDs are firing you trigger.
There's no problem using temp tables, provided that they're in scope at the time the trigger fires.
Given that the trigger can fire at any time, on any connection, the only scope that makes sense is within the body of the trigger:
ALTER TRIGGER [dbo].[trg_HosFile_Delete]
ON [dbo].[hosfile] FOR DELETE
AS
CREATE TABLE #pys (pyGuid uniqueidentifier not null/*I'm guessing*/)
insert into #pys(pyGuid)
SELECT EntryGuid AS pyGuid FROM er000 AS er
insert into t2(C1) select pyGuid from #pys
(To be honest, I'm not sure if you could access a temp table from an outer scope, and don't have an instance handy to test it. But, even if you can, it would make for a very brittle trigger)
If you use ##pys (notice the double # sign) it will be globally available after its creation. That might help in your case.
Try to use SELECT INTO to create and populate the temporary table. There are some restrictions when using a temp table inside a trigger.

Need a sql statement to do upate and insert at the same time

I need a sql statement, to insert a new row in one database table and update an existing row in another database table based on some conditions.
Is there a way to do this? To insert a row in one table and update a row in another database table in one sql statement?
Thanks in advance!
Yes, they are called Transactions, and are implemented with START TRANSACTION and COMMIT/ROLLBACK with something like:
START TRANSACTION;
INSERT INTO ...
UPDATE table2 SET name='TOTO' WHERE type=1;
COMMIT;
EDIT
This is not in fact one SQL query, but the operation is done atomically - and I think that is what you need.
A single SQL statement allows you to update one table, not several; if that statement is a MERGE then you can specify insert/update/delete actions but still targeting just the same one target table.
If you just want consistency, use transactions; until a transaction is committed, changes within it are not visible to the outside world.
If you want that a single update (which you cannot control) resulted in a coordinated insert, use an on update trigger in the table being updated. The trigger would insert appropriate row(s) into other table(s).
You can use Trigger to update second table on insert of first table
Yes, it's possible with stored procedures.
Watch this: Stored procedures

SQL Trigger - help with fundamentals

I rarely write triggers. I can use help setting up the thing.
CREATE TRIGGER audit_tableName
ON dbo.tableNameAudit
AFTER CREATE, UPDATE, DELETE on tableName
AS
BEGIN
--Get Created,updated,deletes items
INSERT into dbo.tableNameAudit(columns) VALUES ([allCUDitems])
END
GO
How do I get an iterate any CREATED, UPDATED, DELETED items that caused the trigger?
check out this msdn article.
the short of it are there are 2 special tables, inserted and deleted, that are accessible in your trigger. inserted will contain updated rows and inserted rows, while deleted will contain updated rows and deleted rows.
make sure that you understand that for a batch operation a trigger is only fired one time, so be sure to handle the possibility of multiple rows being present in those tables.
Triggers have access to two pseudo tables: INSERTED and DELETED. As their name suggests, these pseudo tables will contain all the values added or removed from the table. An update will cause a row in each of the pseudo-tables. The structure of these pseudo-tables is identical with the structure of the table on which the table is declared.
In addition the UPDATE() function inside a trigger will return TRUE for columns that were updated.
You can use INSERTED.[COLUMN] OR
SELECT [COLUMN]
FROM INSERTED
This on SQL Server.
Hope it helps.

Under what conditions would a Sybase trigger not be called?

I have a couple of triggers in a Sybase ASE database that are fired upon updates to two tables: Docs and Trans.
The triggers are defined as shown here:
For Docs:
CREATE TRIGGER dbo.Index_Change_Docs
ON dbo.docs
FOR INSERT,UPDATE AS
IF UPDATE(DOCTYPE) OR UPDATE(BATCH_NO) OR UPDATE(SCANDATE) OR
UPDATE(PERIOD_START_DATE) OR UPDATE(PERIOD_END_DATE)
OR UPDATE(DISPATCH_ID) OR UPDATE(DISPATCH_NAME) OR UPDATE(CHECKNUM) OR
UPDATE(CHECKAMT)
BEGIN
INSERT INTO
DOCID_SYNC (IS_DOC_ID, CRTN_DT, SYNC_STATUS_CDE)
SELECT Inserted.DOCID, GETDATE(), "N" FROM Inserted
END
For Trans:
CREATE TRIGGER dbo.Index_Change_Trans
ON dbo.Trans
FOR INSERT,UPDATE AS
IF UPDATE(TRANSNUM) OR UPDATE(CONTRACT) OR UPDATE(FRANCHISE) OR UPDATE(SSN) OR
UPDATE(STATE_CODE) OR UPDATE(TRANSTYPE)
OR UPDATE(AGENCYNUM) OR UPDATE(LOCKBOXBATCHNUM) OR UPDATE(PRODUCTCODE)
BEGIN
INSERT INTO
DOCID_SYNC (IS_DOC_ID, CRTN_DT, SYNC_STATUS_CDE)
SELECT DOCID, GETDATE(), "N" FROM DOCS
WHERE Transnum = (SELECT Inserted.TransNum from Inserted)
END
It appears the behavior of these triggers is different, depending on how updates to those tables are made.
In one case, these tables are updated via two stored procedures (Insert_Docs_SP and Insert_Trans_SP). When this happens, each trigger is fired once (once for Docs, one for Trans) and everything works as expected.
In another case, these tables are updated within a Sybase transaction with two database updates. Here, the first update is done via inline SQL in the calling application (which fires the Trans trigger.) The second update is done via a stored procedure - Insert_Docs_SP, the same as in the other case - which does not fire a trigger.
Perhaps there is something about how transactions are handled that I am not understanding?
In both of your triggers, the trigger is only inserting into docid_sync table if certain columns are updated. Are you sure that the stored procedure is updating one of the columns in the trigger? Triggers are also not called if it is a recursive update from a trigger call, but that doesn't seem to be the case here.
The other possibility is if the calling transaction disabled the trigger with the set triggers off command. I would start with ensuring that the stored procedure is updating one of the columns in the trigger checks.
One other question: Is the same row being updated twice, in the inline SQL And stored procedure in your error case, or are they updating two different rows?
I found the answer - it's in the order of execution. I thought one of the triggers wasn't being fired - in this case the Index_Change_Trans trigger - but in fact it was. I didn't see the results, however, because this trigger is relying on entries in the Docs table.
INSERT INTO
DOCID_SYNC (IS_DOC_ID, CRTN_DT, SYNC_STATUS_CDE)
SELECT DOCID, GETDATE(), "N" FROM DOCS
WHERE Transnum = (SELECT Inserted.TransNum from Inserted)
So, in cases where the Trans table was updated before the Docs table, the run of the Trans trigger would not show an update in the Docid_Sync table - since at this point there were no entries in the Docs table with the appropriate Transnum value. In these cases, the Docid_Sync table only has one entry, the result of the Docs trigger.
In other instances, the Docs table is updated first, and then the Trans table. In these instances, the Docid_Sync table has two entries - one as the result of the Docs trigger, and another as the result of the Trans trigger.