I am trying to do a simple upsert query in SQL. This query works in SQL Server
IF (EXISTS (SELECT * FROM TableName WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId))
BEGIN
UPDATE TableName
SET "SomeColumn" = #SomeValue
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId;
END
ELSE
BEGIN
INSERT INTO TableName VALUES (#SomeId, #SomeOtherId, #SomeValue);
END
However, our Unit tests run on Sqlite and in general we want to write vanilla SQL, so this IF ELSE won't work.
I was trying to pull it off with CASE WHEN but I can't get it right. Can somebody post a working Sqlite query?
Thanks in advance,
Marko
If there is (or you can create) a unique constraint for the combination of the columns SomeId and SomeOtherId, then you might use UPSERT like this:
INSERT INTO TableName(SomeId, SomeOtherId, SomeColumn)
VALUES(#SomeId, #SomeOtherId, #SomeValue)
ON CONFLICT(SomeId, SomeOtherId) DO
UPDATE SET SomeColumn = #SomeValue;
If not then use 2 statements:
UPDATE TableName
SET SomeColumn = #SomeValue
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId;
INSERT INTO TableName (SomeId, SomeOtherId, SomeColumn)
SELECT #SomeId, #SomeOtherId, #SomeValue
WHERE NOT EXISTS (
SELECT 1 FROM TableName
WHERE SomeId = #SomeId AND SomeOtherId = #SomeOtherId
);
The UPDATE statement will succeed only if there is a row under the conditions you specify, otherwise it will do nothing.
The INSERT statement will succeed only if there is not a row under the conditions you specify, otherwise it will do nothing.
Related
I am trying to capture if my SQL Query have 0 rows or multiple rows. If it has 0 rows then I will insert, if 1 will perform an update, if > 1 will perform additional analysis.
Is there a way I can see if my query resulted in x results or no results in automation anywhere?
Any assistance will be appreciated.
You can make use of if exists and if not exists and check if rows exists or not, or even if there are multiple before doing the insert.
Here is a simple example using if not exists where if the row doesn't exist on dbo.Table it will insert a row. If it already exists then the ID will be logged to an Error table.
declare #InsertID int = 5, #Name nvarchar(max) = 'some name'
if ((select count(1) from dbo.Table where ID = #InsertID) > 1) -- detect error; more than one record for an id
begin
insert into dbo.Error (ErrorID, ErrorDate)
select #InsertID, getdate()
end
else if not exists (select 1 from dbo.Table where ID = #InsertID) -- no record exists for ID, insert it
begin
insert into dbo.Table (ID, Name)
select #InsertID, #Name
else if exists (select 1 from dbo.Table where ID = #InsertID) -- update the single record
begin
update dbo.Table set Name = #Name where ID = #InsertID
end
A2019 returns the results of a SQL Query as a table...
You could have an if statement right after your query which checks to see if the row count of the returned table is > 0 then take action accordingly.
Browsing on various examples on how to create a "good" UPSERT statement shown here, I have created the following code (I have changed the column names):
BEGIN TRANSACTION
IF EXISTS (SELECT *
FROM Table1 WITH (UPDLOCK, SERIALIZABLE), Table2
WHERE Table1.Data3 = Table2.data3)
BEGIN
UPDATE Table1
SET Table1.someColumn = Table2.someColumn,
Table1.DateData2 = GETDATE()
FROM Table1
INNER JOIN Table2 ON Table1.Data3 = Table2.data3
END
ELSE
BEGIN
INSERT INTO Table1 (DataComment, Data1, Data2, Data3, Data4, DateData1, DateData2)
SELECT
'some comment', data1, data2, data3, data4, GETDATE(), GETDATE()
FROM
Table2
END
COMMIT TRANSACTION
My problem is, that it never does the INSERT part. The INSERT alone works fine. The current script only does the update part.
I have an idea that the insert is only good, if it can insert the entire data it finds (because of the select query)? Otherwise it won't work. If so, how can I improve it?
I have also read about the MERGE clause and would like to avoid it.
//EDIT:
After trying out few samples found on the internet and explained here, I re-did my logic as follows:
BEGIN TRANSACTION
BEGIN
UPDATE table1
SET something
WHERE condition is met
UPDATE table2
SET helpColumn = 'DONE'
WHERE condition is met
END
BEGIN
INSERT INTO table1(data)
SELECT data
FROM table2
WHERE helpColumn != 'DONE'
END
COMMIT TRANSACTION
When trying other solutions, the INSERT usually failed or ran for a long time (on a few tables, I can accept it, but not good, if you plan to migrate entire data from one database to another database).
It's probably not the best solution, I think. But for now it works, any comments?
Instead of
if (something )
update query
else
insert query
Structure your logic like this:
update yourTable
etc
where some condition is met
insert into yourTable
etc
select etc
where some condition is met.
You cannot check this in general, like you are doing. You have to check each ID from Table 2 if it exists in Table 1 or not. If it exists, then update Table 1 else insert into Table 1. This can be done in following way.
We are going to iterate on Table 2 for each ID using CURSORS in SQL,
DECLARE #ID int
DECLARE mycursor CURSOR
FOR
SELECT ID FROM Table2 FORWARD_ONLY --Any Unique Column
OPEN mycursor
FETCH NEXT FROM mycursor
INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT 1 FROM Table1 WHERE ID = #ID)
UPDATE t1 SET t1.data= T2.data --And whatever else you want to update
FROM
Table1 t1
INNER JOIN
Table2 t2
ON t1.ID = t2.ID --Joining column
WHERE t1.id = #ID
ELSE
INSERT INTO Table1
SELECT * FROM Table2 WHERE ID = #ID
FETCH NEXT FROM mycursor
INTO #ID
END
CLOSE mycursor
DEALLOCATE mycursor
I want to update the records name,appid in the table1 with matching id. Below statement will update the table1 values with below statement
update table1 set name=#name,appid=#appid where id=#id
I want one more condition. Update all the records for this id,but appid should not update if (#appid is null or id=54). How can i make restriction(condition) on one column(appid). Or should i have to write another update statement? I can format the above query. Please help
update table1 set
name = #name,
appid = (case when #appid is null or id=54 then appid else #appid end)
where id=#id
update table1 set name=#name,
appid= Case when id=54 then appid else Coalesce(#appid,appid) end where id=#id
Does this help you?
update
table1
set name=#name,
appid=ISNUL(#appid, appid)
where
id=(CASE WHEN #id=54 THEN id+1 ELSE #id END)
If I need to SELECT a value from a table column (happens to be the primary key column) based on a relatively complex WHERE clause in the stored procedure, and I then want to update that record without any other concurrent stored procedures SELECTing the same record, is it as simple as just using a transaction? Or do I also need to up the isolation to Repeatable Read?
It looks like this:
Alter Procedure Blah
As
Declare #targetval int
update table1 set field9 = 1, #targetval = field1 where field1 = (
SELECT TOP 1 field1
FROM table1 t
WHERE
(t.field2 = 'this') AND (t.field3 = 'that') AND (t.field4 = 'yep') AND (t.field9 <> 1))
return
I then get my targetval in my program so that I can do work on it, and meanwhile I don't have to worry about other worker threads grabbing the same targetval.
I'm talking SQL 2000, SQL 2005, and SQL 2008 here.
Adding ROWLOCK,UPDLOCK to the sub query should do it.
ALTER PROCEDURE Blah
AS
DECLARE #targetval INT
UPDATE table1
SET field9 = 1,
#targetval = field1
WHERE field1 = (SELECT TOP 1 field1
FROM table1 t WITH (rowlock, updlock)
WHERE ( t.field2 = 'this' )
AND ( t.field3 = 'that' )
AND ( t.field4 = 'yep' )
AND ( t.field9 <> 1 ))
RETURN
Updated
The currently accepted answer to this question does not use updlock. I'm not at all convinced that this will work. As far as I can see from testing in this type of query with a sub query SQL Server will only take S locks for the sub query. Sometimes however the sub query will get optimised out so this approach might appear to work as in Query 2.
Test Script - Setup
CREATE TABLE test_table
(
id int identity(1,1) primary key,
col char(40)
)
INSERT INTO test_table
SELECT NEWID() FROM sys.objects
Query 1
update test_table
set col=NEWID()
where id=(SELECT top (1) id from test_table )
Query 2
update test_table
set col=NEWID()
where id=(SELECT max(id) from test_table)
I want to create a stored procedure that performs insert or update operation on a column if
that column does not contains a value that already exists in database it should allow insert when COUNT(field) = 0 or update when COUNT(field)=0 or 1 And I should know that either of these operation is performed or not.
Please solve my problem using COUNT not Exists because that won't work for UPDATE.
I am working in ASP.net - I have two columns of a table that are needed to be kept unique without using the unique constraint. So I want a procedure like this:
create proc usp_checkall #field1 varchar(20),
#field2 varchar(20),
#ID int,
#count int output
Now your query on updating/inserting #field1 & #field2 on basis of #id
If you happen to have SQL Server 2008, you could also try:
MERGE dbo.SomeTable AS target
USING (SELECT #ID, #Field_1, #Field_2) AS source (ID, Field_1, Field_2)
ON (target.ID = source.ID)
WHEN MATCHED THEN
UPDATE SET Field_1 = source.Field_1, Field_2 = source.Field_2
WHEN NOT MATCHED THEN
INSERT (ID, Field_1, Field_2)
VALUES (source.ID, source.Field_1, source.Field_2)
Use:
INSERT INTO your_table
(column)
VALUES
([ your_value ])
WHERE NOT EXISTS (SELECT NULL
FROM your_table
WHERE t.column = [ your_value ])
That will work on SQL Server, MySQL, Oracle, Postgres. All that's needed is to use the db appropriate variable reference. IE: For MySQL & SQL Server:
INSERT INTO your_table
(column)
VALUES
( #your_value )
WHERE NOT EXISTS (SELECT NULL
FROM your_table
WHERE t.column = #your_value)
To see if anything was inserted, get the value based on ##ROWCOUNT if using SQL Server. Use SQL%ROWCOUNT if you are using Oracle.
if Exists select * from Yourtable WHere Your Criteria
begin
update ...
end
else
begin
insert ...
end
This kind of approach will do the trick. #AlreadyExisted could be an OUTPUT parameter on the sproc for your calling code to check once it's returned.
DECLARE #AlreadyExisted BIT
SET #AlreadyExisted = 0
IF EXISTS(SELECT * FROM YourTable WHERE YourField = #FieldValue)
BEGIN
-- Record already exists
SET #AlreadyExisted = 1
UPDATE YourTable
SET....
WHERE YourField = #FieldValue
END
ELSE
BEGIN
-- Record does not already exist
INSERT YourTable (YourField,....) VALUES (#FieldValue,.....)
END