Continue inserting data in tables skipping duplicate data issue - sql-server

set xact_abort off;
begin tran
DECLARE #error int
declare #SQL nvarchar(max)
set #SQL=N'';
select #SQL=some select query to fetch insert scripts
begin try
exec sp_executesql #SQL
commit
end try
begin catch
select #error=##Error
if #error=2627
begin
continue inserting data
end
if #error<>2627
begin
rollback
end
end catch
I am unable to continue inserting data when any duplicate data comes. Is there any alternative way to continue running SQL queries irrespective of duplicate data? I don not want to alter the index or table.

I am unable to continue inserting data when any duplicate data comes. Is there any alternative way to continue running sql queries irrespective of duplicate data. I dont want to alter the index or table.
What you can do is change the insert scripts as you call them, in this pseudo statement:
select #SQL=some select query to fetch insert scripts
Change the generation script: instead of generating INSERT INTO ... VALUES(...) statements, generate IF NOT EXISTS(...) INSERT INTO ... VALUES(...) statements
These insert statements should first check if a key already exists in the table. If your insert statements are of the form
INSERT INTO some_table(keycol1,...,keycolN,datacol1,...,datacolM)VALUES(keyval1,...,keyvalN,dataval1,...,datavalM);
You can rewrite those as:
IF NOT EXISTS(SELECT 1 FROM some_table WHERE keycol1=keyval1 AND ... AND keycolN=keyvalN)
INSERT INTO some_table(keycol1,...,keycolN,datacol1,...,datacolM)VALUES(keyval1,...,keyvalN,dataval1,...,datavalM);
Change the generation script: instead of generating INSERT INTO ... SELECT ..., generate INSERT INTO ... SELECT ... WHERE NOT EXISTS(...) statements
You can change these statements to only insert if the key does not exist in the table yet. Suppose your insert statements are of the form:
INSERT INTO some_table(keycol1,...,keycolN,datacol1,...,datacolN)
SELECT _keycol1,...,_keycolN,datacol1,...,datacolN
FROM <from_clause>;
You can rewrite those as:
INSERT INTO some_table(keycol1,...,keycolN,datacol1,...,datacolN)
SELECT _keycol1,...,_keycolN,datacol1,...,datacolN
FROM <from_clause>
WHERE NOT EXISTS(SELECT 1 FROM some_table WHERE keycol1=_keycol1 AND ... AND keycolN=_keycolN);
Replace the target table name in #SQL with a temporary table (a so-called staging table), then insert from the temporary table to the target table using WHERE NOT EXISTS(...)
This way you would not have to change the insert generation script. First create a temporary table that has the exact same structure as the target table (not including the primary key). Then replace all instances of the target table name in #SQL with the name of the temporary table. Run the #SQL and afterwards insert from the temporary table to the target table using a WHERE NOT EXISTS(...).
Suppose the target table is named some_table, with key columns key_col1,...,key_colN and data columns datacol1, ..., datacolM.
SELECT * INTO #staging_table FROM some_table WHERE 1=0; -- create staging table with same columns as some_table
SET #SQL=REPLACE(#SQL,'some_table','#staging_table');
EXEC sp_executesql #SQL;
INSERT INTO some_table(keycol1,...,keycolN,datacol1,...,datacolN)
SELECT st.keycol1,...,st.keycolN,st.datacol1,...,st.datacolN
FROM #staging_table AS st
WHERE NOT EXISTS(SELECT 1 FROM some_table WHERE keycol1=st.keycol1 AND ... AND keycolN=st.keycolN);
DROP TABLE #staging_table;

Related

SQL Server Create Table Variable to hold records which will be inserted into permanent Table after truncating permanent table

I have a table with around 7 million rows which I need to perform a truncate of the table. I am going to do this like the following:
BEGIN TRY
BEGIN TRANSACTION
Declare #RecsToKeep Table
(
Id int
)
SELECT Id
FROM RealTable
Where CONVERT (DATE, CreatedDate) > '2017-08-16'
Declare #KeepTheseRecs Table
(
Id int
)
Insert into #KeepTheseRecs
Select *
From RealTable Where Id IN (Select Id From #RecsToKeep)
Truncate Table RealTable
Insert into RealTable
Select *
From #KeepTheseRecs
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
The real table and table variable have the same column structure. Is this the correct way to do this?
First, you haven't changed anything in the table based off your query. You are simply moving the records from A to B and back to A.
A simpler method would be to skip the move all together.
delete from RealTable
where someColumn = 'someValue' --or what ever condition you want
If you are really going to stage the records, you're going to at least want a WHERE clause on that Insert Into statement. I really don't see why you need to do this though.

Truncate existing table within a stored procedure then insert fresh data

I have a stored procedure that returns a result set. After that I insert this result set into created real table. And then I am using that real table create SSRS reports.
So, something like this:
CREATE PROCEDURE Test
AS
DECLARE #TempTable TABLE(..)
INSERT INTO #TempTable
SELECT...
FROM ...
WHERE ...
SELECT * FROM #TempTable
--============================
INSERT INTO RealTable EXEC [dbo].[Test]
How can I modify this stored procedure so every time it executed it will truncate table with existing data and then insert a fresh one?
So I need something like that:
create procedure Test
as
TRUNCATE RealTable
DECLARE #TempTable TABLE(..)
INSERT INTO #TempTable
SELECT...
FROM...
WHERE...
SELECT * FROM #TempTable INTO RealTable
Or should I just create agent job that would run command something like:
Truncate Table RealTable
INSERT INTO RealTable EXEC [dbo].[Test]
Am I on a right way in terms of logic?
Dont TRUNCATE. Use a MERGE Statement.
CREATE PROCEDURE Test
AS
MERGE RealTable TRGT
USING SourceTable SRCE
ON SRCE.[Column] = TRGT.Column --use columns that can be joined together
WHEN MATCHED THEN UPDATE
SET TRGT.Column1 = SRCE.Column1,
TRGT.Column2 = SRCE.Column2
....................
WHEN NOT MATCHED BY TARGET THEN INSERT
VALUES
(
SRCE.Column1,
SRCE.Column2,
.....................
)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
What's the purpose of the truncate if you are inserting the same data?
What should happen if you have more then 1 concurrent user?
another thing you can do:
1.
insert into TargetTable
select * from SourceTable
2.
rebuild indexes on TargetTable
3.
exec sp_rename SourceTable, SourceTable_Old
exec sp_rename TargetTable, SourceTable
drop table SourceTable_Old
this is an old way of entire table data refresh without much impact, when table variable was not an option.
this is what you probably need as you are directly inserting from #TempTable to RealTable.
create procedure Test
as
BEGIN
TRUNCATE TABLE RealTable
INSERT INTO RealTable
SELECT...
FROM someothertable
WHERE...
END

Null values INSERTED in trigger

I want to copy content of one table to another table in the same database.
For this I wrote trigger on source table which triggered on AFTER INSERT UPDATE, there are 2 uniqueidentifier fields in the table which generates values based on newid() as default binding. Based on this uniqueidentifier I am checking whether the record is present on the destination table or not if present then it will update and if not present then insert dataset into the table.
Problem is when i insert a new record the INSERTED in trigger give me NULL values for the uniqueidentifier fields.
In may case only one row is either update or insert so cursor is not used.
Below is my code, I am getting null values in #OriginalTable_MoveDataUID and #OriginalTable_ProcedureUID. Both the MoveDataUID and ProcedureUID are uniqueidentifier fileds.
Please share your thoughts or any alternative for this.
ALTER TRIGGER [dbo].[spec_ref_movedata_procedures_ToUpdate]
ON [dbo].[spec_ref_movedata_procedures]
AFTER INSERT, UPDATE
AS
BEGIN
SET XACT_ABORT ON
BEGIN DISTRIBUTED TRANSACTION
DECLARE #OriginalTable_MoveDataUID NVarchar (100)
DECLARE #OriginalTable_ProcedureUID NVarchar (100)
DECLARE #PresentInHistoryYesNo int
SELECT #OriginalTable_MoveDataUID= MoveDataUID,#OriginalTable_ProcedureUID=ProcedureUID FROM INSERTED
-- inserted for checking purpose
INSERT INTO ERP_Test_NK_spec_ref_movedata_procedures_history_2 (MovedataUID,ProcedureUID) VALUES
(#OriginalTable_MoveDataUID,#OriginalTable_ProcedureUID)
SELECT #PresentInHistoryYesNo = count(*) from spec_ref_movedata_procedures_history WHERE MoveDataUID=#OriginalTable_MoveDataUID AND ProcedureUID=#OriginalTable_ProcedureUID
IF #PresentInHistoryYesNo = 0
BEGIN
-- insert opertions
print 'insert record'
END
ELSE IF #PresentInHistoryYesNo = 1
BEGIN
-- update opertions
print 'update record'
END
COMMIT TRANSACTION
SET XACT_ABORT OFF
END
Instead of using variables, you could do this:
INSERT INTO ERP_Test_NK_spec_ref_movedata_procedures_history_2 (MovedataUID,ProcedureUID)
SELECT MoveDataUID,ProcedureUID FROM INSERTED

Syntax for SQL Trigger to Insert Data in another DB and also to update any field in another db adfter a field is edited

Here is the scenario - I will be specific. I have a "bridged" DB on Sql Called [Fulcrum_Xfer] I use this bridged because the Main Db called [Fulcrum UAT] is using a bigint datatype for some fields and thereby displaying in my Access front end "#Deleted data" in all fields - This behavior CANNOT be changed in the present design (the bigint has to stay) so I have the exact table name and fieldnames in my [Fulcrum_Xfer] DB - the OrderNO field in Orders table in [Fulcrum_Xfer] is int and there is no primary key
What I need to have done by tomorrow under threat of some "you let us down" is the following
the table that initially gets data inserted or updated into is called Orders and is in the [Fulcrum_Xfer] database that structure is as follows
OrderNo int Unchecked
OrderDate smalldatetime Unchecked
ApplicationTenantLinkId int Unchecked
OrderStatus int Unchecked
the table that receives the triggered data from Orders in FulCrum_Xfer is called Orders and it is in Database Fulcrum UAT
The structure is
OrderNo bigint Unchecked Primarykey
OrderDate smalldatetime Unchecked
ApplicationTenantLinkId Bigint Unchecked
OrderStatus int Unchecked
I need two trigger statements that will insert a new record into Orders in [Fulcrum UAT] after I insert it into Orders in [FulCrum_Xfer]
and
I need a trigger that will update any field in Orders in [Fulcrum UAT] when I make a change in Orders in [Fulcrum_Xfer]
I do not know where the trigger goes other than maybe Database Triggers in [FulCrum_XFer] but I get freaked out by the template syntax (do not think I need all that) and I do not know how to write the syntax for each task
I am a very experienced VB / VBA developer and have used ADO for building and calling stored procedures on SQL but have never had to do this type of task on the SQL Server - please do not treat me like a dunce - but this is very important in my job right now.
Well, of cousre I have no way to test it, but I think this is how you'd write the INSERT trigger:
USE [Fulcrum_Xfer]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER dbo.trOrders_Insert
ON dbo.Orders
AFTER INSERT AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Just INSERT everything from the [inserted] pseudotable into
--the target table
INSERT INTO [Fulcrum UAT].dbo.Orders
(OrderNo, OrderDate, ApplicationTenantLinkId, OrderStatus)
SELECT OrderNo, OrderDate, ApplicationTenantLinkId, OrderStatus
FROM inserted;
END
GO
Copy and paste this into a Query window in Management Studio and execute it.
Here's how I'd do the UPDATE trigger. Again, untested ...
USE [Fulcrum_Xfer]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER dbo.trOrders_Update
ON dbo.Orders
AFTER UPDATE AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Just UPDATE everything matching [inserted] pseudotable
--into the target table
--(NOTE: This assumes that UPDATES will never change the PK/OrderNo)
UPDATE [Fulcrum UAT].dbo.Orders
SET OrderDate = ins.OrderDate,
ApplicationTenantLinkId
= ins.ApplicationTenantLinkId,
OrderStatus = ins.OrderStatus
FROM [Fulcrum UAT].dbo.Orders As tar
JOIN inserted as ins ON tar.OrderNo = ins.OrderNo;
--(also, performance may not be great as the JOIN columns are
-- different datatypes)
END
GO
Given:
Database db1 with table t1 and fields (username1, password1)
Database db2 with table t2 and fields (username2, password2)
If you want insert or update t2 in db2 when changes (assume insert) occurred in db1, you should add trigger to t1 in db1:
CREATE TRIGGER `trigger_name` AFTER INSERT ON `t1`
FOR EACH ROW INSERT INTO `db2`.`t2`( `username2`, `password2`)
VALUES ( new.username1, new.password1)
(I am assuming both databases are hosted on the same server.)
Try This
USE BioStar;// Which data base you want to create trigger
GO
CREATE TRIGGER trgAfterInsertnew ON [dbo].[TB_EVENT_LOG]
FOR INSERT
AS
declare #nDateTime int;
declare #nReaderIdn int;
declare #nEventIdn int;
declare #nUserID int;
declare #nIsLog smallint;
declare #nTNAEvent smallint;
declare #nIsUseTA smallint;
declare #nType smallint;
select #nDateTime=i.nDateTime from inserted i;
select #nDateTime=i.nReaderIdn from inserted i;
select #nEventIdn=i.nEventIdn from inserted i;
select #nUserID=i.nUserID from inserted i;
select #nIsLog=i.nIsLog from inserted i;
select #nTNAEvent=i.nTNAEvent from inserted i;
select #nIsUseTA=i.nIsUseTA from inserted i;
select #nType=i.nType from inserted i;
insert into [HRM].dbo.Device_Data
(nDateTime,nReaderIdn,nEventIdn,nUserID,nIsLog,nTNAEvent,nIsUseTA,nType)
values(#nDateTime,#nDateTime,#nEventIdn,#nUserID,#nIsLog,#nTNAEvent,#nIsUseTA,#nType);
--set #audit_action='Inserted Record -- After Insert Trigger.';
PRINT 'AFTER DELETE TRIGGER fired.'
GO

DROP TABLE fails for temp table

I have a client application that creates a temp table, the performs a bulk insert into the temp table, then executes some SQL using the table before deleting it.
Pseudo-code:
open connection
begin transaction
CREATE TABLE #Temp ([Id] int NOT NULL)
bulk insert 500 rows into #Temp
UPDATE [OtherTable] SET [Status]=0 WHERE [Id] IN (SELECT [Id] FROM #Temp) AND [Group]=1
DELETE FROM #Temp WHERE [Id] IN (SELECT [Id] FROM [OtherTable] WHERE [Group]=1)
INSERT INTO [OtherTable] ([Group], [Id]) SELECT 1 as [Group], [DocIden] FROM #Temp
DROP TABLE #Temp
COMMIT TRANSACTION
CLOSE CONNECTION
This is failing with an error on the DROP statement:
Cannot drop the table '#Temp', because it does not exist or you do not have permission.
I can't imagine how this failure could occur without something else going on first, but I don't see any other failures occurring before this.
Is there anything that I'm missing that could be causing this to happen?
possibly something is happening in the session in between?
Try checking for the existence of the table before it's dropped:
IF object_id('tempdb..#Temp') is not null
BEGIN
DROP TABLE #Temp
END
I've tested this on SQL Server 2005, and you can drop a temporary table in the transaction that created it:
begin transaction
create table #temp (id int)
drop table #temp
commit transaction
Which version of SQL Server are you using?
You might reconsider why you are dropping the temp table at all. A local temporary table is automatically deleted when the connection ends. There's usually no need to drop it explicitly.
A global temporary table starts with a double hash (f.e. ##MyTable.) But even a global temp table is automatically deleted when no connection refers to it.
I think you aren't creating the table at all, because the statement
CREATE TABLE #Temp ([Id] AS int)
is incorrect. Please, write it as
CREATE TABLE #Temp ([Id] int)
and see if it works.
BEGIN TRAN
IF object_id('DATABASE_NAME..#TABLE_NAME') is not null
BEGIN
DROP TABLE #TABLE_NAME
END
COMMIT TRAN
Note:Please enter your table name where TABLE_NAME and database name where it says DATABASE_NAME

Resources