Update trigger not working correctly - sql-server

I have two tables abstractDetails and auditAbstractDetails. I have a web form from where a person submits details about abstract (title, background, objective etc.) and it inserts value into abstractDetails table.
Now I have written a trigger so whenever a person updates his Form and submit it again, it should populate new values into abstractDetails as well as it should populate old values and New values in the AuditabstractDetails table ( title,background,objective..... auditTitle,auditBackground.....)
old value should store in AuditabstractDetails tables under the columns title, background etc. and new values will be stored under the columns auditTitle,auditBackground etc.)
here is my trigger:
USE [Abstract]
GO
/****** Object: Trigger [dbo].[trgAuditabstractDetails] Script Date: 09/28/2016 11:45:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[trgAuditabstractDetails]
ON [dbo].[abstractDetails]
FOR UPDATE
AS
BEGIN
SET NOCOUNT ON
delete from AuditabstractDetails where Id IN (SELECT I.Id
FROM Inserted I);
insert into AuditabstractDetails(Id, abstractInfoId, title, background,
objective, design, result, Audittitle, Auditbackground,
Auditobjective, Auditdesign, Auditresult)
-- case 1: ID unchanged
SELECT I.Id, I.abstractInfoId, D.title, D.background, D.objective,
D.design, D.result,
I.title, I.background, I.objective, I.design, I.result
FROM Inserted I
JOIN Deleted D on I.Id=D.Id;
END
GO
after this when I am updating the value of form (title, background etc.) in the abstractDetails table from the backend (from DB by editing the value in abstractDetails table), it is working perfect. But when I am updating it through the form and submitting it, It is updating New values in both columns ( title, auditTitle etc..), It is not storing old values in specific columns , instead it is storing new values in both the columns.
abstractDetails table
===========================================
Id |title | background | Result
-------------------------------------------
1 Abs1 backAbs2 resAbs2
2 Abs2 backAbs2 resAbs2
-------------------------------------------
Expected Result:
AuditabstractDetails table
===============================================
Id |title | background | Result | AuditTitle | auditBackground |auditResult
----------------------------------------------------------------------------
1 Abs1 backAbs2 resAbs2 Audit1 auditback1 auditres1
2 Abs2 backAbs2 resAbs2 Audit2 auditback2 auditres2
----------------------------------------------------------------------------
ActualResult:
AuditabstractDetails table
===============================================
Id |title | background | Result | AuditTitle | auditBackground |auditResult
----------------------------------------------------------------------------
1 Audit1 auditback1 auditres1 Audit1 auditback1 auditres1
2 Audit2 auditback2 auditres2 Audit2 auditback2 auditres2
----------------------------------------------------------------------------
Need help

It sounds like the problem isn't with the trigger, but is with whatever's saving your data. If it works as desired from SQL Server but fails when the UI is making the call, then you need to check the UI to see what's going on. It seems likely that the UI is updating the record more than once. I would test this by removing the delete portion of your trigger and seeing how many rows you end up with in your audit table.

Related

How to efficiently replace long strings by their index for SQL Server inserts?

I have a very large DataTable-Object which I need to import from a client into an MS SQL-Server database via ODBC.
The original Data-Table has two columns:
* First column is the Office Location (quite a long string)
* Second column is a booking value (integer)
Now I am looking for the most efficient way to insert these data into an external SQL-Server. My goal is to replace each office location automatically by an index instead using the full string because each location occurs VERY often in the initial table.
Is this possible via a trigger or via a view on the SQL-server?
At the end I want to insert the data without touching them in my script because this is very slow for these large amount of data and let the optimization done by the SQL Server.
I expect that if I do INSERT the data including the Office location, that SQL Server looks up an index for an already imported location and then use just this index. And if the location did not already exist in the index table / view then it should create a new entry here and then use the new index.
Here a sample of the data I need to import via ODBC into the SQL-Server:
OfficeLocation | BookingValue
EU-Germany-Hamburg-Ostend1 | 12
EU-Germany-Hamburg-Ostend1 | 23
EU-Germany-Hamburg-Ostend1 | 34
EU-France-Paris-Eifeltower | 42
EU-France-Paris-Eifeltower | 53
EU-France-Paris-Eifeltower | 12
What I do need on the SQL-Server is something like these 2 tables as a result:
OId|BookingValue OfficeLocation |Oid
1|12 EU-Germany-Hamburg-Ostend1 | 1
1|23 EU-France-Paris-Eifeltower | 2
1|43
2|42
2|53
2|12
My initial idea was, to write the data into a temp-table and have something like an intelligent TRIGGER (or a VIEW?) to react on any INSERT into this table to create the 2 desired (optimized) tables.
Any hint are more than welcome!
Yes, you can create a view with an INSERT trigger to handle this. Something like:
CREATE TABLE dbo.Locations (
OId int IDENTITY(1,1) not null PRIMARY KEY,
OfficeLocation varchar(500) not null UNIQUE
)
GO
CREATE TABLE dbo.Bookings (
OId int not null,
BookingValue int not null
)
GO
CREATE VIEW dbo.CombinedBookings
WITH SCHEMABINDING
AS
SELECT
OfficeLocation,
BookingValue
FROM
dbo.Bookings b
INNER JOIN
dbo.Locations l
ON
b.OId = l.OId
GO
CREATE TRIGGER CombinedBookings_Insert
ON dbo.CombinedBookings
INSTEAD OF INSERT
AS
INSERT INTO Locations (OfficeLocation)
SELECT OfficeLocation
FROM inserted where OfficeLocation not in (select OfficeLocation from Locations)
INSERT INTO Bookings (OId,BookingValue)
SELECT OId, BookingValue
FROM
inserted i
INNER JOIN
Locations l
ON
i.OfficeLocation = l.OfficeLocation
As you can see, we first add to the locations table any missing locations and then populate the bookings table.
A similar trigger can cope with Updates. I'd generally let the Locations table just grow and not attempt to clean it up (for no longer referenced locations) with triggers. If growth is a concern, a periodic job will usually be good enough.
Be aware that some tools (such as bulk inserts) may not invoke triggers, so those will not be usable with the above view.

How to get data from the current row in INSTEAD OF trigger?

For example, we have a table named 'Names':
id | name
-----+------
1 | Mary
2 | Sue
3 | John
and this trigger:
CREATE TRIGGER TRG_insofdel
ON Names
INSTEAD OF DELETE
AS
BEGIN
-- here I need to get some data from the current row
END
and then I call
DELETE FROM Names
WHERE id = 1
How can I get Mary's (id == 1) name in the trigger?
What is going on with the 'deleted' table in this case?
The MSDN documentation does explain but it isn't laid out very clearly.
In a trigger, SQL server automatically makes 2 special in-memory tables available to you:
inserted: the data which was added to the table (for insert and update statements)
deleted: the data which was removed from the table (for update and delete statements)
They have the same columns as the actual table, but are completely read-only - you cannot add columns or indexes to them or change the data inside them.
So in your example, to get the name of the person being removed, you can do the following inside the trigger:
DECLARE #name varchar(100);
SELECT #name = name from deleted;
Important note
Be aware tho that if multiple rows were deleted from the table, then deleted will contain multiple rows - the trigger is not called individually once for each row.

Clone row and maintain a reference to cloned row

I want to clone some row from a table, the row must be selected using a specific condition, but I also need to save in a temporary table N pair(sourceRowID, destinationRowID)
I've tried using OUTPUT but I can't use fields of the source row
INSERT INTO myTable(Value1, Value2)
OUTPUT myTable.ID, Inserted.ID
INTO #tempTable(sourceRowID, destinationRowID)
SELECT Value1, Value2
FROM myTable
WHERE Value2 > 10
Is there a solution to this? Unfortunately I am constraint to use SQL server 2008
UPDATE:
For now this is my solution:
First of all I write the inserted record using the OUTPUT instruction to the #tempTable ensuring that the records are inserted ordered by ID
At this point I've the #tempTable that contains, for example
sourceRowID | destinationRowID
-------------------------------
NULL | 12
NULL | 15
NULL | 16
NULL | 23
than I update #tempTable retrieving again the same record with the same WHERE condition joining the #tempTable and the retrieved record by RowNumber ensuring again that the records are retrieved ordered by destinationRowID, in this way the order of new and old record must be the same, and with the update I'll obtain the #tempTable with correct sourceRowID and destinationRowID

How to update last modified user using windows auth info?

I've a table sales containing sales records in SQL Server. I need a a column modified_by which shows the actor (user) of the last modification. Column modified_by should be filled by the user's ID related to the Windows Authentication.
id content modified_by
----------- ----------- -----------
1 foo Tom
2 bar Jack
If Tom updates Jack's record, then for the record 2, the column modified_by will show Tom instead.
This UPDATE action should be done automotically by the server for every record modification. Can it be possible ? Should I use trigger to do it ?
We can use TRIGGER to check rows after INSERT or UPDATE statement
CREATE TRIGGER dbo.after_update ON dbo.sales
AFTER INSERT, UPDATE
AS
UPDATE dbo.sales
SET modified_by = SYSTEM_USER
FROM inserted
WHERE inserted.id = dbo.sales.id
MSDN: CREATE TRIGGER (Transact-SQL)
update table
set lastmodifiedby =suser_sname()
More info here
you also can create a table with last modified as default ..
create table tt
(
id int,
lastmodifiedby varchar(100) default suser_sname()
)

compare and insert only new records to sqlite database

I have sqlite local database. I want to insert only fresh data from remote server to local database.Since there is no time field,it is difficult to insert only new records.How can i acheive this? I require this for my hybrid mobile app. Any helps apperciated..Thanks in advance.
Two tables:
my local db table is
tbl_orders
id name age
1 yyy 30
2 xxx 20
my remote db table is
tbl_orders
id name age
1 yyy 36
2 xxx 20
3 vvv 40
4 zzz 37
In the above the remote table contains additionally two records and also the value in first record(age column) get changed.now i want to insert and update this(i.e 1st,3rd,4th) to my local sqlite table without deleting and reinserting the whole table.
You should add a UNIQUE constrain in id.
Redefining your local table:
CREATE TABLE tbl_orders(UNIQUE id, name, age);
or without redefining table
CREATE UNIQUE INDEX tbl_orders_id ON tbl_orders(id);
With constrain, your updates become a single statement:
INSERT OR REPLACE INTO local.tbl_orders SELECT * FROM remote.tbl_orders;
Your table is replicated in two DB?
If yes, you can do an INSERT with NOT EXISTS clause in WHERE condition. Alternatively, add datetime field in your source table.
Another way:
Add a boolean field in your source DB (fl_sent), populated by a trigger when create a new row in your DB or update them. Default value is false, and when you want to syncronize your DBs your select is based on this field
SELECT * FROM myTable WHERE fl_sent = 0
For a more complete answer please post your tables.
EDIT AFTER COMMENT:
Solution 1:
Add field date in your remote table (source) (if you want, you write a trigger about toggle this field) and then execute your sendable query based on this date.
Solution 2:
Add field flag (fl_sent) set by zero (if you want, you write a trigger about toggle this field) and then execute your sendable query based on this flag.

Resources