So I'm trying, in a single query, to only insert a row if it doesn't exist already.
My query is the following:
INSERT INTO [dbo].[users_roles] ([user_id], [role_id])
SELECT 29851, 1 WHERE NOT EXISTS (
SELECT 1 FROM [dbo].[users_roles] WHERE user_id = 29851 AND role_id = 1)
Sometimes (very rarely, but still), it generates the following error:
Violation of PRIMARY KEY constraint 'PK_USERS_ROLES'. Cannot insert duplicate key in object 'dbo.users_roles'. The duplicate key value is (29851, 1).
PK_USERS_ROLES
is [user_id], [role_id]
. Here is the full SQL of the table's schema:
create table users_roles
(
user_id int not null
constraint FK_USERS_ROLES_USER
references user,
role_id int not null
constraint FK_USERS_ROLES_USER_ROLE
references user_role,
constraint PK_USERS_ROLES
primary key (user_id, role_id)
)
Context:
This is executed by a PHP script hosted on an Apache server, and "randomly" happens once out of hundreds of occurrences (most likely concurrency-related).
More info:
SELECT @@VERSION
gives:
Microsoft SQL Server 2008 R2 (SP2) - 10.50.4000.0 (X64) Jun 28 2012 08:36:30 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack)
SQL Server version:
SQL Server 2008 R2
Transaction Isolation level:
ReadCommitted
This is executed within an explicit transaction (through PHP statements, but I figure the end result is the same)
Questions:
Could someone explain why/how this is happening?
What would be an efficient way to safely insert in one go (in other words, in a single query)? I've seen other answers such as this one but the solutions are meant for stored procedures.
Thanks.