Reputation: 522
I have this script in my program. It inserts new datasets for every entry in user_settings
into my pricelist
table. It works fine.
INSERT INTO [pricelist]
([ID]
,[plf]
,[vdf]
,[vdt]
,[plID]
,[usID])
SELECT
NEWID()
,5.5
,'2017-01-02 00:00:00'
,'2027-01-03 00:00:00'
,'8020F2FA1C80XXXXXXXXXXXXXXX'
,ID
FROM [user_settings]
But if I need to re-run the script, in case run 1 canceled for any reason. I get duplicate entries in table pricelist
. How can I avoid this? Thanks in advance.
Upvotes: 0
Views: 100
Reputation: 69769
A simple way is to use NOT EXISTS
:
INSERT INTO [pricelist]
([ID]
,[plf]
,[vdf]
,[vdt]
,[plID]
,[usID])
SELECT
NEWID()
,5.5
,'2017-01-02 00:00:00'
,'2027-01-03 00:00:00'
,'8020F2FA1C80XXXXXXXXXXXXXXX'
,ID
FROM [user_settings] AS us
WHERE NOT EXISTS (SELECT 1 FROM [pricelist] AS p WHERE p.UsID = us.ID);
Although, this is not thread safe, and you might still end up with duplicates if you meet a race condition. If something should be unique, then give it a unique constraint, e.g.
ALTER TABLE PriceList ADD CONSTRAINT UQ_PriceList__usID UNIQUE (usID);
This will guarantee no duplicates. The most threadsafe INSERT
I know of is to use MERGE WITH (HOLDLOCK)
:
MERGE [PriceList] WITH (HOLDLOCK) AS p
USING [user_settings] AS US
ON us.ID = p.usID
WHEN NOT MATCHED THEN
INSERT ([ID], [plf], [vdf], [vdt], [plID], [usID])
VALUES (NEWID(), 5.5, '2017-01-02 00:00:00', '2027-01-03 00:00:00',
'8020F2FA1C80XXXXXXXXXXXXXXX', us.[ID]);
This is still no substitute for creating your constraint though.
N.B. It is not quite clear from your question how you define a duplicate, for brevity I have assumed it is just usID
in the table, but if it is more columns, all of the principles outlined above still apply
ADDENDUM
If the above is not working, then you may need to add more conditions to your join to include more columns:
MERGE PriceList WITH (HOLDLOCK) AS p
USING
( SELECT ID = NEWID(),
plf = 5.5,
vdf = '2017-01-02 00:00:00',
vdt = '2027-01-03 00:00:00',
plID = '8020F2FA1C80XXXXXXXXXXXXXXX',
usID = us.ID
FROM user_settings AS us
GROUP BY us.ID -- only needed if us.ID is not unique
) AS us
ON us.usID = p.usID
AND us.plf = p.plf
AND us.vdf = p.vdf
AND us.vdt = p.vdt
AND us.plID = p.plID
WHEN NOT MATCHED THEN
INSERT (ID, plf, vdf, vdt, plID, usID)
VALUES (us.ID, us.plf, us.vdf, us.vdt, us.plID, us.usID);
Finally, part of the problem could be existing duplicates, which you can remove using something like:
DELETE t
FROM ( SELECT *, RowNumber = ROW_NUMBER() OVER(PARTITION BY plf, vdf, vdt, plID, usID ORDER BY ID)
FROM PriceList
) AS t
WHERE t.RowNumber > 1;
Upvotes: 0
Reputation: 93704
You should consider adding a unique constraint
on your table to avoid such problems.
Use NOT Exists
to avoid inserting duplicate data. Based on your comments, you need to check for all the columns except the ID
INSERT INTO [pricelist]
([ID],[plf],[vdf],[vdt],[plID],[usID])
SELECT [ID],[plf],[vdf],[vdt],[plID],[usID]
FROM (SELECT Newid() ID,
5.5 AS plf,
'2017-01-02 00:00:00' AS vdf,
'2027-01-03 00:00:00' AS vdt,
'8020F2FA1C80XXXXXXXXXXXXXXX' AS plID,
ID AS usID
FROM [user_settings]) u
WHERE NOT EXISTS (SELECT 1
FROM pricelist p
WHERE u.plf = p.plf
AND u.vdf = p.vdf
AND u.vdt = p.vdt
AND u.plID = p.plID
AND u.usID = p.usID)
Upvotes: 1
Reputation: 48197
INSERT INTO [pricelist]
SELECT NEWID(), u.*
FROM [user_settings] u
LEFT JOIN [pricelist] p
ON u.[id] = p.[id]
WHERE p.[id] IS NULL
Upvotes: 0