simple insert procedure, check for duplicate - sql

I am creating a program that is going to insert data into a table which is pretty simple
But my issue is I want my insert statement to make sure that it isnt inserting duplicate data
I want to somehow check the table the data is going into to make sure that there isnt a row with the same indivualid and categoryid and value
So if I am inserting
indivualid = 1
categorid = 1
value = 1
and in my table there is a row with
indivualid = 1
categorid = 1
value = 2
my data would still be inserted
but if there was a row with
indivualid = 1
categorid = 1
value = 1
then it wouldnt
I tried this
IF #value = 'Y'
OR #value = 'A'
OR #value = 'P'
AND NOT EXISTS
(SELECT categoryid,
individualid
FROM ualhistory
WHERE categoryid = #cat
AND individualid = #id)
INSERT INTO individuory(categoryid, individualid, value, ts)
VALUES (#cat,
#id,
#yesorno,
getdate())
but it still inserts duplicates.

You can do that in the following manner:
insert into
individuory(categoryid, individualid, value, ts)
VALUES (#cat, #id, #yesorno, getdate())
where not exists
(select 1 from individuory where categoryid=#cat and individualid=#id)
Now, the exact problem with your approach is that you are not associating the ORs and therefore, the condition becomes true and always inserts the data. You can change your statement to this:
if ((#value = 'Y' or #value = 'A' or #value = 'P')
and not EXISTS
(SELECT categoryid, individualid FROM ualhistory WHERE categoryid = #cat
and individualid = #id) )
INSERT INTO individuory(categoryid, individualid, value, ts)
VALUES (#cat, #id, #yesorno, getdate())
And I think it will work also.

ALTER TABLE individuory
ADD CONSTRAINT myConstarint
UNIQUE (categoryid, individualid, value)

Add a UNIQUE constraint on (individualid, categoryid, value) and the server won't let you insert a duplicate row.
http://msdn.microsoft.com/en-us/library/ms189862.aspx

Related

How to insert value in SQL table if not exists

I'm new in SQL. I'm trying to insert data into a SQL table. If I insert for the first time it works but if I try to do a new insert I get the error
Violation of UNIQUE KEY constraint.
The unique key constraint is on (uc, start_date). The error occurs because there is already the record (-1, 1900-01-01) in the table. Here is my code:
insert into tableA ([start_date],[end_date],[uc],[desc],[ind_sus])
select '1900-01-01' [start_date]
,'9999-12-31'[end_date]
,case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end [uc]
,'' [desc]
,0 [ind_sus]
from tableB b
where right([DIM], 2) NOT IN (select uc from tableA a
where a.uc = right([DIM], 2)
and convert(date,b.[DATETRIAL]) between a.start_date and a.end_date)
group by case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end
The data that I'm trying to insert fulfills the when condition of the case and therefore another (-1, 1900-01-01) as key. I tried:
case when not exists(select uc from tableA where uc = '-1') then '-1'
to insert only if the data doesn't exist. It didn't work because I have to put the same code in the group by clause and I realized that I cannot do a subquery in the group by clause. So, is there a way to check at the case clause level if a value already exist before inserting? Or should I rewrite the request in another way? Database can't be modified
I need suggestions please.
In order to be able to check and insert data when not exists you need to use MERGE operator (see docs for more info).
Since you did not provide us with test data, I'm not sure I can easily update your query, so here is an example I made up to show you how to do things you need using MERGE.
Create table and insert 1 row with id = 1:
create table some_table(id int primary key, text_col varchar(10));
insert into some_table values(1, 'first');
Try to insert a line with same id
insert into some_table values(1, 'another first'); -- it fails of course
same thing using merge
merge into some_table -- target table
using
(select 1 id, 'another first' text_col) new_data -- source data
on some_table.id = new_data.id -- column to check on
when not matched then
insert (id, text_col) values(new_data.id, new_data.text_col);
I hope this helps
My try to change your query to merge would be like that
(keep in mind I did not tested it so fixing syntax or possible data errors is up to you)
merge into tableA a
using (select uc
,'1900-01-01' [start_date]
,'9999-12-31'[end_date]
,case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2) end [uc]
,'' [desc]
,0 [ind_sus]
from tableB b
group by case when right([DIM], 1) = '|' then '-1'
else right([DIM], 2)
end) b
on a.right([DIM], 2) = b.uc
and convert(date,b.[DATETRIAL]) between a.start_date and a.end_date
when not matched then
insert([start_date],[end_date],[uc],[desc],[ind_sus])
values(b.start_date, b.end_date, b.uc, b.desc, b.ind_sus)

SQL Server 2008: Sql Insert/Update into another table using insertion IDs output from another table

I have a procedure for insert in multiple dependent tables (update in case record exist). I have input parameters as comma separated string which I am reading in table.
After 1st insertion I am getting InsertedIds in another table variable.
I am struggling over how to do insert in 2nd table. I have following input parameters for 2nd table:
Declare #IdsToBeUpdated table (primary key identity pkey, id int) -- values are 1,-1,3,-1
Declare #CommentsTobeInserted table( primary key identity pkey, comment varchar (max)) -- values are 'com1', 'com2', 'com3'
-1 input in table #IdsToBeUpdated depicts insertion for the corresponding rows in all input tables and value other than -1 depicts that records at that pkey value in all other tables (#CommentsTobeInserted table as in example) have to be updated.
So after first insertion I am getting the inserted ids for rows with -1 value. #InsertedIds = 4,5
So my Ids list logically would become.. 1,4,3,5.
But I am stuck now how to insert/update records in second table respectively.
2nd table would be like follows:
Pkey Primary key identity, commentIds(coming from inserted ids and #IdsToBeUpdated), comments.
I have added one more InsertedIds column in #CommentsTobeInserted. If I could fill it with right InsertedId against correct row, I guess I would be able to do insert/update in 2nd table. And where the value is Id in new column I would do insert, where it's null, I would perform update using #IdsToBeUpdated table.
But currently none of my approach is working. I am new to SQL. Any help would be highly appreciated.
Following is some portion of script for better understanding. I have added first insertion script as well.
USE [Demo]
GO
/****** Object: StoredProcedure [dbo].[USP_NewRequest_Insert] Script Date: 2/11/2016 2:50:34 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[USP_NewRequest_Insert]
-----------------------------------
--------- SomeInput parameters
---------for first insertion omitted
--------------------------------
#IdsToBeUpdated varchar(MAX), --Values are 23|-1|32|-1|-1
#CommentList AS VARCHAR(MAX), --Values 'C2'|'C4'|'C5'|'C6'|'C7'
#MCodeList VARCHAR(MAX), --Values 'M2'|'M4'|'M5'|'M6'|'M7'
#CustomerIdsList VARCHAR(MAX), ----Values 'Cust2'|'Cust4'|'Cust5'|'Cust6'|'Cust7'
#ReturnValue AS INT OUTPUT,
------------------Data is in the order it has to be inserted.. where IDs exist in #IdsToBeUpdated, updation would be done. For -1 values, insertion.
AS
BEGIN
BEGIN TRANSACTION
--------------------------Split input strings aand insert in Table variable----------------------------
declare #MCodes Table (pkey int primary key identity, MCode varchar(20))
insert into #MCodes select s.Item from [dbo].UDF_SplitString(#MCodeList, '|') s
declare #CusCodes Table (pkey int primary key identity, CusCode varchar(200))
insert into #CusCodes select s.Item from [dbo].UDF_SplitString(#CustomerIdsList, '|') s
declare #ReqDetailsIds Table (pkey int primary key identity, Id Int)
insert into #ReqDetailsIds select Convert(INT,RTRIM(LTRIM(s.Item))) from [dbo].UDF_SplitString(#IdsToBeUpdated, '|') s
where s.Item is not null and RTRIM(LTRIM(s.Item)) <>''
declare #ProductComments Table (pkey int primary key identity, Comment Varchar(max), insertedId int null)
insert into #ProductComments(Comment) select s.Item from [dbo].UDF_SplitString(#CommentList, '|') s
DECLARE #intErrorCode int;
------------------------------------------------------------------------------------------------------------
-----------------First Insertion which returns inserted IDs for 2nd insertion
------------------------------------------------------------------------------------------------------------------
---Insert/Update product details in [RequestDetails]
Declare #InsertedIDList Table (pkey int primary key identity, ID int); --------Table to read inserted Ids. Used in query below
-----------------------Insert query in case Detail id = -1
INSERT INTO [dbo].[RequestDetails]
[MCode]
,[CustomerIds]
,[ExpectedVolume]------Some parameters coming for first insertion in input
,[StatusCode])
Output INSERTED.ReqDetailId Into #InsertedIDList(ID)
SELECT A.MCode, B.CusCode, E.Vol,1
FROM #MCodes A
JOIN #CusCodes B ON B.pkey = A.pkey
JOIN #ExpectedVols E ON E.pkey = A.pkey
JOIN #ReqDetailsIds G ON G.pkey = A.pkey
WHERE G.Id = -1 --If id = -1, insert
---------------------------Update Query for rest records
UPDATE [dbo].[RequestDetails]
SET [MCode] = upd.MCode
,[CustomerIds] = upd.CusCode
,[ExpectedVolume] = upd.ExVol
,[StatusCode] = 1
FROM(
SELECT A.MCode, B.CusCode, E.ExVol, G.Id
FROM #MCodes A
JOIN #CusCodes B ON B.pkey = A.pkey
JOIN #ExpectedVols E ON E.pkey = A.pkey
JOIN #ReqDetailsIds G ON G.pkey = A.pkey
WHERE G.Id <> -1
) upd
WHERE upd.Id = dbo.RequestDetails.ReqDetailId
IF(##Error<>0)
BEGIN
SET #intErrorCode = ##Error
GOTO ERROR
END
ELSE
BEGIN
SET #ReturnValue=1
END
---------------------------------------------------------------------------
----------------------------Now similarly I have to do insert/update in Comments Table. But
----------------------------Comments table has RequestDetails Id column as foreign key. So
----------------------------now the challange is to add the rows with Inserted ID where value was = -1
----------------------------in input. We have got the IDs corresponding to -1 values from above insertion
----------------------------in the #InsertedIDList Table variable
-----------------------------------------------------------------------------------------
----------------------------Following is what I have tried so far. But I am not able to insert
----------------------------correct InsertedId against correct record.
----------------------------------------------------------------------------------------
-----------------------Here I tried to insert the new generated ids against corresponding comments in table variable.
-----------------------So that I can perform insert where value is not null. As NULL would be inserted where new ID has not been created
-----------------------and corresponding updated ID exists in input (Values not equal to -1)
-------------------------------------------------------------------------------------------------
Update #ProductComments set insertedId = i.ID from ---------This query is not working
(select A.pkey, B.id as detailId, row_number() over (order by (select 0)) as row_num from
#ProductComments A
JOIN #ReqDetailsIds B ON B.pkey = A.pkey) as mappedNewIds right join
#InsertedIDList i on i.pkey = mappedNewIds.row_num
where mappedNewIds.pkey = [#ProductComments].pkey
----Insert in CommentsTable for New Comments against request
---------------------------------
INSERT INTO [dbo].CommentsTable
( ReqDetailId, Comments, CreatedOn )
SELECT A.insertedId, A.Comment, GETDATE()
FROM #ProductComments A
where A.insertedId is not null
-----Update Query
------------------------------------------------------------------------------------------
UPDATE [dbo].[CommentsTable]
SET [ReqDetailId] = upd.Id
,[Comments] = upd.Comment
,[CreatedOn] = GetDate()
FROM(
SELECT A.Comment, B.Id
FROM #ProductComments A
JOIN #ReqDetailsIds B ON B.pkey = A.pkey
WHERE A.insertedId is not null
) upd
WHERE upd.Id = dbo.CommentsTable.ReqDetailId
END
select * from CommentsTable;
---------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
IF(##Error<>0)
BEGIN
SET #intErrorCode = ##Error
GOTO ERROR
END
ELSE
BEGIN
SET #ReturnValue=1
END
COMMIT TRANSACTION
ERROR:
IF (#intErrorCode <> 0) BEGIN
SET #ReturnValue = 0;
ROLLBACK TRANSACTION
END
END

How to update a temporary table with a value from a select statement?

I have created a temporary table to hold some values like this:
CREATE TABLE #TempCount (PendingOrders INT, OpenOrders INT, ClosedOrders INT);
I want to update the columns with a value from a SELECT statement as such:
UPDATE #TempCount
SET PendingOrders =
(
SELECT
COUNT(OrderID) AS 'PendingOrders'
FROM
dbo.Products
WHERE
OrderStatus = 1
)
However nothing seems to get updated. I expected PendingOrders to show a number but it doesn't get anything entered in. The column is empty. The same applies to the other columns - nothing gets updated.
How could I solve this?
You need a row in order to update it. Do one "initializing" INSERT first:
INSERT INTO #TempCount VALUES(0, 0, 0)
Seems to me like you need an insert statement first to generate the row.
INSERT #TempCount (PendingOrders)
SELECT COUNT(OrderID) AS 'PendingOrders'
FROM dbo.Products
WHERE OrderStatus = 1
If you just want to hold single values then consider variables
declare #PendingOrders int
set #PendingOrders = ( SELECT COUNT(OrderID)
FROM dbo.Products
WHERE OrderStatus = 1 )
select #PendingOrders, #OpenOrders, #ClosedOrders
Use this syntax:
UPDATE t
SET t.xxx=p.xxx
FROM #TempCount t, Products p
WHERE ......
Subselect is not always necessary.

How to Delete the Existing data based on Where clause condition using Merge

i have written a merge Statement where i am facing trouble to delete the data basing on Where Clause Condition.
Let me explain my scenario Clearly
For example i have inserted Data from Source to Target based on Date Key Condition.Take an Instance 10 Records Inserted.
For example some changes in the records and it has been updated through the Merge Statement .
For the Same Date key based on Conditions now three records has came and need to be inserted and rest should be deleted for that Date Key.
How i need to proceed on this before 10 records are not getting deleted and new records adding for that one
My Example Code :
DELETE FROM #Table1
CREATE TABLE #Table1
(ID INT ,Name VARCHAR(30),DATEKEY INT)
INSERT INTO #Table1 (ID,Name,DATEKEY)VALUES (1,'Mohan',20131231)
INSERT INTO #Table1 (ID,Name,DATEKEY)VALUES (2,'Raj',20131231)
INSERT INTO #Table1 (ID,Name,DATEKEY)VALUES (3,'Majjaa',20131231)
INSERT INTO #Table1 (ID,Name,DATEKEY)VALUES (4,'Majjaa',20131231)
CREATE TABLE #Table2
(ID INT ,Name VARCHAR(30),DATEKEY INT)
DECLARE #i_DateKey INT
SET #i_DateKey = '20131231'
MERGE #Table2 AS T
USING (
SELECT pdp.ID
,pdp.Name
,pdp.DATEKEY
FROM #Table1 AS pdp
WHERE (
pdp.DateKey = #i_DateKey
OR #i_DateKey IS NULL
)
) AS S
ON T.ID = S.ID
AND T.DateKey = S.DateKey
AND T.NAME = S.NAME
WHEN MATCHED
THEN
UPDATE
SET T.NAME = S.NAME
WHEN NOT MATCHED BY TARGET
THEN
INSERT
VALUES (
S.ID
,S.Name
,S.DateKey
)
WHEN NOT MATCHED BY SOURCE
THEN
DELETE ;
Now the target table will be loaded with Rows now if i send the another row for Same Date key then it need to be deleted all the 4 rows and reload the new Row if the new row is same then need to update
i think this is one big mistake,
ON T.ID = S.ID --i am not sure about this
AND T.DateKey = S.DateKey
AND T.NAME = S.NAME -- remove this because this when matched then update will do what ?
WHEN MATCHED
THEN
UPDATE
SET T.NAME = S.NAME

How do I get temp values to be set after an insert has occured in a trigger?

I have a trigger I am working on that will insert rows into a table when another table has inserts or updates applied to it. So far the Update portion works (the column that I'm most concerned with is the Balance column), but when the first row is added for an insert on the Account table, in my AuditTrailCustomerBalance table OldBalance, NewBalance and CustNo are set to NULL. How can I get NewBalance and CustNo to reference to the values that were just inserted into the table from the trigger?
Here is the trigger:
ALTER TRIGGER AuditTrigger
ON Accounts
FOR INSERT, UPDATE
AS
IF UPDATE( Balance )
BEGIN
IF EXISTS
(
SELECT 'True'
FROM Inserted i
JOIN Deleted d
ON i.AccountID = d.AccountID
)
BEGIN
--1. Declare temp variables.
DECLARE #OldBalance NUMERIC( 18, 0 )
DECLARE #NewBalance NUMERIC( 18, 0 )
DECLARE #CustNo INT
--2. Set the variables.
SELECT #OldBalance = Balance FROM deleted
SELECT #NewBalance = Balance FROM inserted
SELECT #CustNo = CustNo FROM inserted
INSERT INTO AuditTrailCustomerBalance( TimeChanged, ChangedBy, OldBalance, NewBalance, CustNo )
VALUES( GETDATE(), SUSER_SNAME(), #OldBalance, #NewBalance, #CustNo )
END
END
GO
And the test statement:
INSERT INTO Custs( CustNo, GivenName, Surname, DOB, SIN )
VALUES( 1, 'Peter', 'Griffen', 'January 15, 1950', '555555555')
INSERT INTO Accounts( CustNo, Type, Balance, AccruedInt, WithdrawalCount )
VALUES( 1, 'Savings', 0, 0, 0 )
UPDATE Accounts SET Balance = 100
WHERE CustNo = 1
I believe that you want something like this:
ALTER TRIGGER AuditTrigger
ON Accounts
FOR INSERT, UPDATE
AS
INSERT INTO AuditTrailCustomerBalance(TimeChanged, ChangedBy,
OldBalance, NewBalance, CustNo )
SELECT GETDATE(), SUSER_SNAME(),
COALESCE(d.Balance,0), i.Balance, i.CustNo
FROM inserted i
left join
deleted d
on
i.AccountNo = d.AccountNo
WHERE
i.Balance <> d.Balance OR
d.Balance IS NULL
As I said in my comments, inserted and deleted can contain multiple rows (or no rows) and so you need to take that into account and write a set-based query that deals with all of those rows - also some rows may have had balance changes and some not - so deciding whether to write any entries based on UPDATE(Balance) was also flawed.
you can if you are sure of your code write something like this :
if (select count(*) from inserted) = 1
and execute your code.
You can for the insert do like this :
insert into AuditTrailCustomerBalance (.....)
select .... from inserted
as already posted, the problem with your trigger is in the calling if you update one row or multiple (same for insert)