4

I have what I thought to be a completely trivial query - insert values into a table if a value with a matching ID does not exist:

BEGIN
   INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
   VALUES (1, 'Internal')
   WHERE NOT EXISTS( SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
END

I get an error around the where statement. Why? How do I accomplish my goal?

enter image description here

VSO
  • 10,409
  • 20
  • 83
  • 166
  • Possible duplicate of [Check if a row exists, otherwise insert](https://stackoverflow.com/questions/639854/check-if-a-row-exists-otherwise-insert) – Complex Oct 16 '17 at 21:19
  • 1
    `BEGIN INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description) SELECT 1, 'Internal' FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID <> 1) END` – Paul Varghese Oct 16 '17 at 21:20
  • @PaulVarghese What it it doesn't exist yet? Then there is no `Contact_Category_ID = 1`; – VSO Oct 16 '17 at 21:22
  • @VSO Check TZHX answer... – Paul Varghese Oct 16 '17 at 21:24

6 Answers6

17

Your problem comes from WHERE being valid for UPDATE/SELECT but INSERT just doesn’t understand what it means.

But you can get around this. Change your code to be like:

BEGIN
   INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
   SELECT 1, 'Internal'
   WHERE NOT EXISTS( SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
END
TZHX
  • 4,946
  • 15
  • 45
  • 55
1

The correct way to handle this is by using a unique index/constraint:

create unique index unq_Contact_Categories_Category_Id on Contact_Categories(Contact_Category_ID);

The database will then guarantee the uniqueness for the column. This prevents race conditions.

You can catch this using try/catch:

BEGIN TRY
   INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
       SELECT 1, 'Internal';
END TRY
BEGIN CATCH
   PRINT 'Ooops';  -- you can even raise an error if you like.
END CATCH;
Gordon Linoff
  • 1,198,228
  • 53
  • 572
  • 709
0

Why not an If statement?

IF NOT EXISTS 
(select * from [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
  begin
    insert into [dbo].[Contact_Categories] (Contact_Category_ID, Description)
    values (1, 'Internal')
  end

This has the advantage of not doing anything if the value exists. Similar to answer provided here: SQL Server IF NOT EXISTS Usage?

Randall
  • 1,349
  • 11
  • 19
0

I would do:

INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID, Description)
   VALUES (1, 'Internal')
   WHERE 1 NOT IN ( SELECT Contact_Category_ID FROM [dbo].[Contact_Categories]) 
Mohamed F
  • 734
  • 1
  • 7
  • 13
0

Try to replace your query with:

BEGIN
     IF NOT EXISTS (SELECT * FROM [dbo].[Contact_Categories] WHERE Contact_Category_ID = 1)
        INSERT INTO [dbo].[Contact_Categories](Contact_Category_ID,Description) VALUES (1, 'Internal')
END
rodmucha
  • 26
  • 2
  • This query must be inside a transaction to prevent race conditions, otherwise someone might insert a row between the time that the table was checked and the insertion of the row. – rodmucha Oct 16 '17 at 22:41
0

I also had the same problem, this is my solution.

insert into Contact_Categories (Contact_Category_ID, Description)
   select 1, 'Internal' 
where not exists 
   (select * from Contact_Categories where Contact_Category_ID = 1 and Description = 'Internal');
rajkanani
  • 75
  • 1
  • 4