56

I have table in which I am inserting rows for employee but next time when I want to insert row I don't want to insert again data for that employee just want to update with required columns if it exits there if not then create new row

How can we do this in SQL Server 2005?

I am using jsp

my query is

String sql="insert into table1(id,name,itemname,itemcatName,itemQty)values('val1','val2','val3','val4','val5')";

if it's first time then insert it into database else if exists update it

how to do?

Rob
  • 25,569
  • 15
  • 73
  • 87
ybc126
  • 2,189
  • 4
  • 16
  • 15

5 Answers5

73

Try to check for existence:

IF NOT EXISTS (SELECT * FROM dbo.Employee WHERE ID = @SomeID)

    INSERT INTO dbo.Employee(Col1, ..., ColN)
    VALUES(Val1, .., ValN)

ELSE

    UPDATE dbo.Employee
    SET Col1 = Val1, Col2 = Val2, ...., ColN = ValN
    WHERE ID = @SomeID

You could easily wrap this into a stored procedure and just call that stored procedure from the outside (e.g. from a programming language like C# or whatever you're using).

Update: either you can just write this entire statement in one long string (doable - but not really very useful) - or you can wrap it into a stored procedure:

CREATE PROCEDURE dbo.InsertOrUpdateEmployee
       @ID INT,
       @Name VARCHAR(50),
       @ItemName VARCHAR(50),  
       @ItemCatName VARCHAR(50),
       @ItemQty DECIMAL(15,2)
AS BEGIN
    IF NOT EXISTS (SELECT * FROM dbo.Table1 WHERE ID = @ID)
       INSERT INTO dbo.Table1(ID, Name, ItemName, ItemCatName, ItemQty)
       VALUES(@ID, @Name, @ItemName, @ItemCatName, @ItemQty)
    ELSE
       UPDATE dbo.Table1
       SET Name = @Name,
           ItemName = @ItemName,
           ItemCatName = @ItemCatName,
           ItemQty = @ItemQty
       WHERE ID = @ID
END

and then just call that stored procedure from your ADO.NET code

Lee Taylor
  • 6,091
  • 14
  • 26
  • 43
marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
  • where write above code in above sql string or need create trigger or procedure. – ybc126 Jun 13 '12 at 09:02
  • 1
    writing in single string it will look like String sql="IF NOT EXIST (SELECT*FROM Employee WHERE ID=@someid)INSERT INTO EMPLOYEE (col1,...,colN)values(val1,..,valN)ELSE UPDATE EMPLOYEE SET col1=val1,col2=val2,...,colN=valN WHERE ID=@someID" Will this work. – ybc126 Jun 13 '12 at 09:25
  • @ybc126: if you have the necessary spaces in your SQL - yes. But something like that is **definitely** not advisable! Putting this into a stored procedure (or using an ORM to handle this) would be **much better** – marc_s Jun 13 '12 at 11:23
  • Very often it is recommended to not use `Select * from`. I do not know if it matters when using `IF NOT EXISTS (SELECT * FROM ...` but i would probably use `IF NOT EXISTS (SELECT Id FROM ...` just to avoid using `*`. – surfmuggle Jan 24 '14 at 11:27
  • @threeFourOneSixOneThree: yes, not using `SELECT *` is generally good advice - but in the case of `IF NOT EXISTS()`, it's irrelevant. The `IF NOT EXISTS()` clause will just simply test whether or not at least one row for the given search criteria (`WHERE .....`) exists or not - it's **NOT** actually returning all columns! Using `IF NOT EXISTS(SELECT * ...)` is equivalent and absolutely the same as using `IF NOT EXISTS (SELECT 1 .....)` – marc_s Jan 24 '14 at 11:28
  • The *only* advantage to checking for existence first is readability - for performance, you should always try the INSERT or UPDATE first (will post answer below) – Abacus Jan 16 '15 at 17:28
  • 2
    I am right to assume that the Store Procedure won't handle concurrent requests. If two requests access the same time trying to insert the same primary key, and the primary key does not exist in the table yet, then, the both requests will simultaneously pass the first condition (as the select can be run in parallel). The INSERT, however, needs to be run in exclusion, so one of the queries will add the new record, and the other one will have an exception indicating that there is a duplicate primary key. – Antonio Oct 03 '17 at 08:55
46

You can use @@ROWCOUNT to check whether row should be inserted or updated:

update table1 
set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
where id = 'val1'
if @@ROWCOUNT = 0
insert into table1(id, name, itemname, itemcatName, itemQty)
values('val1', 'val2', 'val3', 'val4', 'val5')

in this case if update fails, the new row will be inserted

Evgeny Gorb
  • 1,015
  • 2
  • 11
  • 22
13

You can check if the row exists, and then INSERT or UPDATE, but this guarantees you will be performing two SQL operations instead of one:

  1. check if row exists
  2. insert or update row

A better solution is to always UPDATE first, and if no rows were updated, then do an INSERT, like so:

update table1 
set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
where id = 'val1'

if @@ROWCOUNT = 0
  insert into table1(id, name, itemname, itemcatName, itemQty)
  values('val1', 'val2', 'val3', 'val4', 'val5')

This will either take one SQL operations, or two SQL operations, depending on whether the row already exists.

But if performance is really an issue, then you need to figure out if the operations are more likely to be INSERT's or UPDATE's. If UPDATE's are more common, do the above. If INSERT's are more common, you can do that in reverse, but you have to add error handling.

BEGIN TRY
  insert into table1(id, name, itemname, itemcatName, itemQty)
  values('val1', 'val2', 'val3', 'val4', 'val5')
END TRY
BEGIN CATCH
  update table1 
  set name = 'val2', itemname = 'val3', itemcatName = 'val4', itemQty = 'val5'
  where id = 'val1'
END CATCH

To be really certain if you need to do an UPDATE or INSERT, you have to do two operations within a single TRANSACTION. Theoretically, right after the first UPDATE or INSERT (or even the EXISTS check), but before the next INSERT/UPDATE statement, the database could have changed, causing the second statement to fail anyway. This is exceedingly rare, and the overhead for transactions may not be worth it.

Alternately, you can use a single SQL operation called MERGE to perform either an INSERT or an UPDATE, but that's also probably overkill for this one-row operation.

Consider reading about SQL transaction statements, race conditions, SQL MERGE statement.

Abacus
  • 1,775
  • 15
  • 21
  • The link to the question you mention is specific to MySql where as this thread is regarding SQL Server which does not have the ON DUPLICATE KEY UPDATE option. Could you clarify which answer you mean or is this a mistake on your part? – Sam Redway Oct 30 '17 at 15:38
13

Here is a useful article by Michael J. Swart on the matter, which covers different patterns and antipatterns for implementing UPSERT in SQL Server:
https://michaeljswart.com/2017/07/sql-server-upsert-patterns-and-antipatterns/

It addresses associated concurrency issues (primary key violations, deadlocks) - all of the answers provided here yet are considered antipatterns in the article (except for the @Bridge solution using triggers, which is not covered there).

Here is an extract from the article with the solution preferred by the author:

Inside a serializable transaction with lock hints:

CREATE PROCEDURE s_AccountDetails_Upsert ( @Email nvarchar(4000), @Etc nvarchar(max) )
AS 
  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  BEGIN TRAN

    IF EXISTS ( SELECT * FROM dbo.AccountDetails WITH (UPDLOCK) WHERE Email = @Email )

      UPDATE dbo.AccountDetails
         SET Etc = @Etc
       WHERE Email = @Email;

    ELSE 

      INSERT dbo.AccountDetails ( Email, Etc )
      VALUES ( @Email, @Etc );

  COMMIT

There is also related question with answers here on stackoverflow: Insert Update stored proc on SQL Server

protasovams
  • 450
  • 8
  • 12
3

You could do this with an INSTEAD OF INSERT trigger on the table, that checks for the existance of the row and then updates/inserts depending on whether it exists already. There is an example of how to do this for SQL Server 2000+ on MSDN here:

CREATE TRIGGER IO_Trig_INS_Employee ON Employee
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON
-- Check for duplicate Person. If no duplicate, do an insert.
IF (NOT EXISTS (SELECT P.SSN
      FROM Person P, inserted I
      WHERE P.SSN = I.SSN))
   INSERT INTO Person
      SELECT SSN,Name,Address,Birthdate
      FROM inserted
ELSE
-- Log attempt to insert duplicate Person row in PersonDuplicates table.
   INSERT INTO PersonDuplicates
      SELECT SSN,Name,Address,Birthdate,SUSER_SNAME(),GETDATE()
      FROM inserted
-- Check for duplicate Employee. If no duplicate, do an insert.
IF (NOT EXISTS (SELECT E.SSN
      FROM EmployeeTable E, inserted
      WHERE E.SSN = inserted.SSN))
   INSERT INTO EmployeeTable
      SELECT EmployeeID,SSN, Department, Salary
      FROM inserted
ELSE
--If duplicate, change to UPDATE so that there will not
--be a duplicate key violation error.
   UPDATE EmployeeTable
      SET EmployeeID = I.EmployeeID,
          Department = I.Department,
          Salary = I.Salary
   FROM EmployeeTable E, inserted I
   WHERE E.SSN = I.SSN
END
Bridge
  • 27,772
  • 8
  • 56
  • 78