Insert using stored procedure - sql

I want to insert a record into multiple tables at single time using a stored procedure. But if it already exists, that record could not be inserted. How can it? I need help. I have link between the tables.
CREATE TABLE [dbo].[tblrole]
(
[roleid] [INT] IDENTITY(1, 1) NOT NULL,
[rolename] [VARCHAR](50) NULL,
PRIMARY KEY CLUSTERED ([roleid] ASC)
)

It's normal that you cannot insert a duplicate record if you have a unique primary key.
You have been talking about multiple tables, but you've schown us just one table definition.
I I've understood well your problem, you would something like this:
create proc insert_data
-- params are coming here
as
if not exists(select 1 from your_target_table1 where column = #condition)
-- your insert comes here
else
-- do nothing or log en error in an error table or do an update
if not exists(select 1 from your_target_table2 where column = #condition)
-- your insert comes here
else
-- do nothing or log en error in an error table or do an update
-- and soon

Related

Insert where not exists but thread safe (I don't want duplicates)

I need to insert values into a table if a value with a matching ID does not exist like in this thread: SQL - Insert Where Not Exists
But I need to make sure if an other thread executes a query in exactly the same time, I won't get two the same rows.
This is my table:
CREATE TABLE [dbo].[Localizations]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](50) NOT NULL,
[regionId] [int] NOT NULL
) ON [PRIMARY]
This my current query which inserts a new localization row if a localization row with regionId = x doesn't exist (unfortunately it works incorrectly - now I have duplicates in my database):
-- firstly I execute something like that (my real queries are more complex):
DECLARE #id int = (SELECT [id] FROM [dbo].[Localizations] WHERE regionId = 1);
-- secondly I execute something like that (my real queries are more complex):
IF (#id IS NULL)
BEGIN
INSERT INTO [dbo].[Localizations]
VALUES ('Test', 1);
END
It caused that now I have MANY rows with the same regionId, I can't remove them now, they are used in different tables :( :( :( Because of that, I can't create the unique constraint on the regionId column because I have duplicates :( :(
Could you tell me if the following query doesn't create duplicates with the same regionId if many threads execute that query in the same time? I have read this thread:
SQL - Insert Where Not Exists
but I am not sure and I don't want to insert more duplicates :(
INSERT INTO [dbo].[Localizations] (name, regionId)
SELECT 'Test', 1
WHERE NOT EXISTS (SELECT *
FROM [dbo].[Localizations]
WHERE regionId = 1)
After you remove the duplicates and add a unique constraint you can change your batch to prevent sessions from attempting to insert duplicates like this:
BEGIN TRANSACTION;
DECLARE #id int = (SELECT [id] FROM [dbo].[Localizations] WITH (UPDLOCK,HOLDLOCK) WHERE regionId = 1);
-- secondly I execute something like that (my real queries are more complex):
IF (#id is null)
BEGIN
INSERT INTO [dbo].[Localizations] VALUES('Test', 1);
END
COMMIT TRANSACTION;
This will force the first query to take and hold an update lock on the row or empty range, which will ensure that the INSERT will succeed, and any other session running this code will block until the transaction is committed.
You already know the answer, you should remove duplicities and add unique constraint. Until then, your data are broken.
If you want just a patch for new data, you can create unique filtered index on regionId, where you filter on regionId > lastDuplicitValue. But if you do not care about duplicities you already have, why care about the new ones?

How to merge rows of one table to another while keeping foreign key constraints on autogenerated columns?

Here are two tables that I have, with Table B referencing Table A:
CREATE TABLE TableA
(
[Id_A] [bigint] IDENTITY(1,1) NOT NULL,
...
CONSTRAINT [PK_TableA_Id_A] PRIMARY KEY CLUSTERED
(
[Id_A] ASC
)
)
CREATE TABLE TableB
(
[Id_B] [bigint] IDENTITY(1,1) NOT NULL,
[RefId_A] [bigint] NOT NULL
...
CONSTRAINT [PK_TableB_Id_B] PRIMARY KEY CLUSTERED
(
[Id_B] ASC
)
)
ALTER TABLE [dbo].[TableB] WITH CHECK ADD CONSTRAINT [FK_Id_A] FOREIGN KEY([RefId_A])
REFERENCES [dbo].[TableA] ([Id_A])
These two tables are part of 2 databases.
Table A and Table B in database 1;
Table A and Table B in database 2.
I need to merge the rows of Table A from database 1 into Table A of database 2 and the rows of Table B from database 1 into Table B of database 2.
I used the SQL Data Import and Export Wizard , checked the Enable Identity Insert option but it fails:
An OLE DB record is available. Source: "Microsoft SQL Server Native
Client 11.0" Hresult: 0x80004005 Description: "Violation of PRIMARY
KEY constraint 'PK_TableB_Id_B'. Cannot insert duplicate key in object
'dbo.TableB'. The duplicate key value is (1).". (SQL Server Import and
Export Wizard)
Which seems to make sense. There are rows in Table B of database 1 that have the same auto-generated PK as rows of Table B in database 2.
QUESTION
In this scenario, how can I merge the tables content from database 1 to the tables of database 2 while maintaining the foreign key constraints?
You can try something like the following. In here we assume that you need to insert all records as new ones (and not compare if some already exist or not). I wrapped both operations in a transaction to ensure that both go OK or none at all.
BEGIN TRY
IF OBJECT_ID('tempdb..#IdentityRelationships') IS NOT NULL
DROP TABLE #IdentityRelationships
CREATE TABLE #IdentityRelationships (
OldIdentity INT,
NewIdentity INT)
BEGIN TRANSACTION
;WITH SourceData AS
(
SELECT
OldIdentity = A.Id_A,
OtherColumn = A.OtherColumn
FROM
Database1.Schema.TableA AS A
)
MERGE INTO
Database2.Schema.TableA AS T
USING
SourceData AS S ON 1 = 0 -- Will always execute the "WHEN NOT MATCHED" operation
WHEN NOT MATCHED THEN
INSERT (
OtherColumn)
VALUES (
S.OtherColumn)
OUTPUT
inserted.Id_A, -- "MERGE" clause can output non-inserted values
S.ID_A
INTO
#IdentityRelationships (
NewIdentity,
OldIdentity);
INSERT INTO Database2.Schema.TableB (
RefId_A,
OtherData)
SELECT
RefId_A = I.NewIdentity,
OtherData = T.OtherData
FROM
Database1.Schema.TableB AS T
INNER JOIN #IdentityRelationships AS I ON T.RefID_A = I.OldIdentity
COMMIT
END TRY
BEGIN CATCH
DECLARE #v_ErrorMessage VARCHAR(MAX) = CONVERT(VARCHAR(MAX), ERROR_MESSAGE())
IF ##TRANCOUNT > 0
ROLLBACK
RAISERROR (#v_ErrorMessage, 16, 1)
END CATCH
This is too long for a comment.
There is no simple way to do this. Your primary keys are identity columns that both start at "1", so the relationships are ambiguous.
You have two options:
A composite primary key, identifying the database source of the records.
A new primary key. You can preserve the existing primary key values from one database.
Your question doesn't provide enough information to say which is the better approach: "merge" is not clearly defined.
I might suggest that you just recreate all the tables. Insert all the rows from table A into a new table. Add a new identity primary key. Keep the original primary key and source.
Then bring the data from Table B into a new table, looking up the new primary key in the new Table A. At this point, the new Table B is finished, except for defining the primary key constraint.
Then drop the unnecessarily columns in the new table A.

SQL Server trigger not acting as expected

I have these two tables:
CREATE TABLE [dbo].[Test_Table1]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[f_id] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[Test_Table2_Tbl]
(
[f_id] [int] IDENTITY(1,1) NOT NULL,
[text] [varchar](500) NULL
) ON [PRIMARY]
And a trigger:
CREATE TRIGGER [dbo].[trg_Test_Trigger_Delete]
ON [dbo].[Test_Table2_Tbl]
AFTER DELETE
AS
INSERT INTO Test_Table2_Tbl (text)
(SELECT id FROM deleted)
UPDATE Test_Table1_Tbl
SET f_id = NULL
WHERE f_id IN (SELECT id FROM deleted)
GO
The keen observer will realize that 'id' does not exist in 'deleted'.
SQL catches that error in the INSERT, but without the INSERT it will let you add the trigger without any complaints.
Why doesn't it catch that error? (Invalid column name 'id'.)
My second question is, why does the UPDATE statement update EVERY column to NULL when id is not found in deleted?
I'm just very confused and need so clarity on why every record matches that WHERE clause.
Your error in the UPDATE is because the query is treated as a correlated subquery:
UPDATE Test_Table1_Tbl
SET f_id = NULL
WHERE Test_Table1_Tbl.f_id IN (SELECT Test_Table1_Tbl.id FROM deleted d);
id doesn't resolve in deleted, so SQL looks out at the next level.
These are the scoping rules for subqueries. That is why you should always use qualified table names when you have subqueries:
UPDATE Test_Table1_Tbl
SET f_id = NULL
WHERE Test_Table1_Tbl.f_id IN (SELECT d.id FROM deleted d);

SQL Server trigger update column from another table

I am trying to create a fairly simple SQL Server trigger, hope someone can help.
I have a table with structure like this:
Table #1:
CREATE TABLE `teg_priority` (
`UCIDN` BIGINT(50) NULL DEFAULT NULL,
`CIDN` BIGINT(50) NOT NULL,
`CustomerName` VARCHAR(200) NOT NULL,
`NGM` VARCHAR(150) NULL DEFAULT NULL,
`Service_Manager` VARCHAR(150) NULL DEFAULT NULL,
`CBS` LONGTEXT NULL,
`Tag` VARCHAR(50) NOT NULL,
PRIMARY KEY (`CIDN`)
)
and another table (table #2):
CREATE TABLE `custalign` (
`UCIDN` BIGINT(20) NOT NULL,
`CIDN` BIGINT(20) NOT NULL,
`CustomerName` VARCHAR(255) NOT NULL,
PRIMARY KEY (`CIDN`)
)
I am trying to set up a trigger where every time a new record is inserted into the first table that the following query will be run as a trigger to update field UCIDN in table 1
update teg_priority
set teg_priority.UCIDN = (select UCIDN from custalign
where teg_priority.CIDN = custalign.CIDN)
The above query works i just don't know how to write it as a trigger statement.
Please help.
CREATE TRIGGER dbo.Teg_priority_after_insert
ON dbo.teg_priority AFTER INSERT
AS
UPDATE inserted
set inserted.UCIDN = (select UCIDN from custalign
where inserted.CIDN = custalign.CIDN)
That's your answer. You might consider a change in approach; assuming it doesn't require a total re-work of your process-flow. I can't really suggest more without knowing what you're ultimately trying to accomplish.
In SQL Server triggers, there is an inserted and a deleted table automatically-generated to which you may refer. Each respectively contains the new and old records as a result of whatever statement AFTER [INSERT],[UPDATE],[DELETE]. The inserted table is accessible to AFTER INSERT and UPDATE triggers, while the deleted table is accessible to AFTER UPDATE and DELETE triggers.
That might be more than you wanted to know, but I thought you'd benefit from a brief explanation of where the inserted table came from in my code.
[Insert all the usual caveats about trying not to use triggers wherever possible here.]
try out this..hope this will helps you
For MySQL
CREATE TRIGGER teg_priorityTrigger AFTER INSERT ON teg_priority
FOR EACH ROW
BEGIN
UPDATE inserted
set inserted.UCIDN = (select UCIDN from custalign
where inserted.CIDN = custalign.CIDN)
END
For SQL Server
CREATE TRIGGER teg_priorityTrigger ON dbo.teg_priority AFTER INSERT
AS
UPDATE inserted
set inserted.UCIDN = (select UCIDN from custalign
where inserted.CIDN = custalign.CIDN)
hope this will helps you...

Trigger for insert on identity column

I have a table A with an Identity Column which is the primary key.
The primary key is at the same time a foreign key that points towards another table B.
I am trying to build an insert trigger that inserts into Table B the identity column that is about to be created in table A and another custom value for example '1'.
I tried using ##Identity but I keep getting a foreign key conflict. Thanks for your help.
create TRIGGER dbo.tr ON dbo.TableA FOR INSERT
AS
SET NOCOUNT ON
begin
insert into TableB
select ##identity, 1;
end
alexolb answered the question himself in the comments above. Another alternative is to use the IDENT_CURRENT function instead of selecting from the table. The drawback of this approach is that it always starts your number one higher than the seed, but that is easily remedied by setting the seed one unit lower. I think it feels better to use a function than a subquery.
For example:
CREATE TABLE [tbl_TiggeredTable](
[id] [int] identity(0,1) NOT NULL,
[other] [varchar](max)
)
CREATE TRIGGER [trgMyTrigger]
ON [tbl_TriggeredTable]
INSTEAD OF INSERT,UPDATE,DELETE
SET identity_insert tbl_TriggeredTable ON
INSERT INTO tbl_TriggeredTable (
[id],
[other]
)
SELECT
-- The identity column will have a zero in the insert table when
-- it has not been populated yet, so we need to figure it out manually
case i.[id]
when 0 then IDENT_CURRENT('tbl_TriggeredTable') + IDENT_INCR('tbl_TriggeredTable')
ELSE i.[id]
END,
i.[other],
FROM inserted i
SET identity_insert tbl_TriggeredTable OFF
END