views:

48

answers:

3

Simple question here.

Context: A Transact-SQL table with an int primary key, and a name that also must be unqiue (even though it's not a primary key). Let's say:

TableID INT,
TableName NVARCHAR(50)

I'm adding a new rows to this able through a stored procedure (and, thus, specifying TableName with a parameter).

Question: What's the best/simplest way to verify if the provided TableName parameter already exist in the table, and to prevent the add of a new row if it's the case?

Is possible to do this directly within my AddNewRow stored procedure?

+5  A: 

To add a unique constraint on TableName and handle the error if you try and insert a duplicate.

This avoids any issues with concurrent transactions inserting a duplicate in between you reading that it is not there and trying your insert.

See this related question.

Martin Smith
Totally valid answer and, I have to admit, the first one that occurred to me. But it has an important caveat: it assumes he can alter the database schema to add such a constraint! :)
djacobson
@djacobson - Good point. `Merge` avoids all that.
Martin Smith
+1  A: 

I would prefer using Unique Constraint on the column and then explicitly checking on for its existance.

Handling an exception will result into Identity increment if present,

Secondly exception can be avoided by checking for existence before insertion which other wise is more expensive operation.

IF EXISTS (SELECT TOP(1) ColName FROM MyTable WHERE ColName=@myParameter)

If using Unique constraint you can also apply Unique Nonclustured index resulting into fast retrieval alongwith.

Shantanu Gupta
But that doesn't take into account concurrency.
Martin Smith
@Martin: What do you mean by "account concurrency". Please explain, I didnt get you
Shantanu Gupta
take into account "concurrency" not "account concurrency" :-) Without any additional locking hints there's nothing to stop 2 transactions both reading that it is not there and proceeding to attempt the insert. I guess the unique constraint would stop this anyway but it's still doing 2 table accesses rather than one. Gaps in the identity column shouldn't matter - if they do then IDENTITY is the wrong thing to be using anyway. All unique constraints are backed up by a unique index.
Martin Smith
@Martin: Yes I do agree with you. Without using Locking there would be concurrency problem.
Shantanu Gupta
+5  A: 

If you're using SQL Server 2008 then you could use a MERGE statement in your sproc:

MERGE INTO YourTable AS target
USING (VALUES (@tableName)) AS source (TableName)
    ON target.TableName = source.TableName
WHEN NOT MATCHED THEN
    INSERT (TableName) VALUES (TableName)

You should still ensure that the TableName column has a UNIQUE constraint.

LukeH
Oh yes. Forgot about that. +1 I actually gave that [as an answer](http://stackoverflow.com/questions/3268866/insert-record-only-if-record-does-not-already-exist-in-table/3268889#3268889) in the past for this as well!
Martin Smith
Can I use both WHEN MATCHED and WHEN NOT MATCHED statements at the same time like a if-else?
asmo
@asmo - Yes. If you wanted to update when matched and insert if not matched you would include both clauses.
Martin Smith