473,385 Members | 1,309 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

How to update if exists else Insert in one SQL statement

In MS Access I can do in one SQL statement a update if exists else a
insert.

Assuming my source staging table is called - SOURCE and my target
table is called - DEST and both of them have the same structure as
follows

Keycolumns
==========
Material
Customer
Year

NonKeyColumns
=============
Sales
In Access I can do a update if the record exists else do a insert in
one update SQL statement as follows:
UPDATE DEST SET DEST.SALES = SOURCE.SALES
from DEST RIGHT OUTER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
This query will add a record in SOURCE into DEST if that record does
not exist in DEST else it does a update. This query however does not
work on SQL 2000

Am I missing something please share your views how I can do this in
SQL 2000.

Thanks
Karen
Jul 20 '05 #1
6 61532
You cannot do that in a Single statement in SQL Server.
You have to do Either

1.

IF EXISTS(SELECT 1 FROM DEST INNER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
--Update Statement
ELSE
--Insert Statement
OR

2.

UPDATE DEST SET DEST.SALES = SOURCE.SALES
from DEST RIGHT OUTER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
IF @@ROWCOUNT = 0
--Insert Statement

--
Roji. P. Thomas
Net Asset Management
https://www.netassetmanagement.com
"Karen Middleton" <ka***********@yahoo.com> wrote in message
news:a5**************************@posting.google.c om...
In MS Access I can do in one SQL statement a update if exists else a
insert.

Assuming my source staging table is called - SOURCE and my target
table is called - DEST and both of them have the same structure as
follows

Keycolumns
==========
Material
Customer
Year

NonKeyColumns
=============
Sales
In Access I can do a update if the record exists else do a insert in
one update SQL statement as follows:
UPDATE DEST SET DEST.SALES = SOURCE.SALES
from DEST RIGHT OUTER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
This query will add a record in SOURCE into DEST if that record does
not exist in DEST else it does a update. This query however does not
work on SQL 2000

Am I missing something please share your views how I can do this in
SQL 2000.

Thanks
Karen

Jul 20 '05 #2
On 11 Nov 2004 00:42:37 -0800, Karen Middleton wrote:
In MS Access I can do in one SQL statement a update if exists else a
insert. (snip)This query will add a record in SOURCE into DEST if that record does
not exist in DEST else it does a update. This query however does not
work on SQL 2000

Am I missing something please share your views how I can do this in
SQL 2000.


Hi Karen,

SQL Server has no such feature. The best way to get the same result is
like this:

BEGIN TRANSACTION
UPDATE Dest
SET Sales = Source.Sales
FROM Dest
INNER JOIN Source
ON Source.Material = Dest.Material
AND Source.Customer = Dest.Customer
AND Source.Year = Dest.Year
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
INSERT Dest (Material, Customer, Year, Sales)
SELECT Material, Customer, Year, Sales
FROM Source
WHERE NOT EXISTS
(SELECT *
FROM Dest
WHERE Source.Material = Dest.Material
AND Source.Customer = Dest.Customer
AND Source.Year = Dest.Year)
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
COMMIT TRANSACTION
Done:
PRINT 'Done'

(untested)

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #3
On Thu, 11 Nov 2004 14:36:26 +0530, Roji. P. Thomas wrote:
You cannot do that in a Single statement in SQL Server.
You have to do Either

1.

IF EXISTS(SELECT 1 FROM DEST INNER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
--Update Statement
ELSE
--Insert Statement
OR

2.

UPDATE DEST SET DEST.SALES = SOURCE.SALES
from DEST RIGHT OUTER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
IF @@ROWCOUNT = 0
--Insert Statement


Hi Roji,

These suggestions will only work as expected if only one row has to be
"upserted". For multi-row operation, option 2 without the IF condition is
(IMO) the only way to do this.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #4
You are right. I was thinking abt the typical parameterized one row insert.
I realized my mistake only after seeing your first post.

Thanks for the correction

--
Roji. P. Thomas
Net Asset Management
https://www.netassetmanagement.com
"Hugo Kornelis" <hugo@pe_NO_rFact.in_SPAM_fo> wrote in message
news:1d********************************@4ax.com...
On Thu, 11 Nov 2004 14:36:26 +0530, Roji. P. Thomas wrote:
You cannot do that in a Single statement in SQL Server.
You have to do Either

1.

IF EXISTS(SELECT 1 FROM DEST INNER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
--Update Statement
ELSE
--Insert Statement
OR

2.

UPDATE DEST SET DEST.SALES = SOURCE.SALES
from DEST RIGHT OUTER JOIN SOURCE
ON (DEST.MATERIAL = SOURCE.MATERIAL AND
DEST.CUSTOMER = SOURCE.CUSTOMER AND
DEST.YEAR = SOURCE.YEAR)
IF @@ROWCOUNT = 0
--Insert Statement


Hi Roji,

These suggestions will only work as expected if only one row has to be
"upserted". For multi-row operation, option 2 without the IF condition is
(IMO) the only way to do this.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)

Jul 20 '05 #5
Hugo & Roji

Many thanks for your tips.

Hugo,

The solution you suggested is perfect but is it possible I can set
some kind of a commit interval for the update and Insert since my
staging table is 2 mill+ I do not want the temp db to bloat with that
size is it possible I can handle this in smaller chunks to optimally
use the tempdb space.

Also, is it possible I can make it generic so that I can pass the
source and target table names and can the stored procedure discover
all the key and non-key columns and do the upsert.

Thanks
Karen

Hugo Kornelis <hugo@pe_NO_rFact.in_SPAM_fo> wrote in message news:<qd********************************@4ax.com>. ..
On 11 Nov 2004 00:42:37 -0800, Karen Middleton wrote:
In MS Access I can do in one SQL statement a update if exists else a
insert.

(snip)
This query will add a record in SOURCE into DEST if that record does
not exist in DEST else it does a update. This query however does not
work on SQL 2000

Am I missing something please share your views how I can do this in
SQL 2000.


Hi Karen,

SQL Server has no such feature. The best way to get the same result is
like this:

BEGIN TRANSACTION
UPDATE Dest
SET Sales = Source.Sales
FROM Dest
INNER JOIN Source
ON Source.Material = Dest.Material
AND Source.Customer = Dest.Customer
AND Source.Year = Dest.Year
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
INSERT Dest (Material, Customer, Year, Sales)
SELECT Material, Customer, Year, Sales
FROM Source
WHERE NOT EXISTS
(SELECT *
FROM Dest
WHERE Source.Material = Dest.Material
AND Source.Customer = Dest.Customer
AND Source.Year = Dest.Year)
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
COMMIT TRANSACTION
Done:
PRINT 'Done'

(untested)

Best, Hugo

Jul 20 '05 #6
On 11 Nov 2004 20:48:16 -0800, Karen Middleton wrote:
Hugo & Roji

Many thanks for your tips.

Hugo,

The solution you suggested is perfect but is it possible I can set
some kind of a commit interval for the update and Insert since my
staging table is 2 mill+ I do not want the temp db to bloat with that
size is it possible I can handle this in smaller chunks to optimally
use the tempdb space.
Hi Karen,

The usual pattern is something like this:

SET ROWCOUNT 10000 -- Adapt this to your needs
WHILE 1 = 1
BEGIN
UPDATE (or DELETE or INSERT)
SET ... = ...
WHERE ..... -- this must somehow exclude the rows
AND ..... -- that were handled in previous iterations
IF @@ROWCOUNT = 0 BREAK
END
SET ROWCOUNT 0

In your situation, you'd have to have two of these loops. The first for
updating existing rows, the second for inserting new rows. The second loop
is easy - if you insert 10,000 rows that don't already exist, the next
iteration will automatically skip these (as they now do exist) and go on
to the next 10,000. The update loop is harder - the only way to prevent
each iteration from simply updating the same set of rows is to compare not
only the primary key columns, but ALL columns - if all are equal, that row
should be excluded. That will result in a bloated query (depending on the
number of columns), with special handling for columns that may be NULL. It
will also be slow, as comparing all columns requires a table scan for the
correlated subquery (and if your staging table is 2 mill+ rows, your dest
table will probably be even bigger). Not nice.

Instead, I'd recommend you to use the following pattern:

CREATE TABLE #TempTable (-- same structure as staging table (Source),
-- constraints not required,
-- but add indexes to optimize for speed)
SET ROWCOUNT 10000 -- Adapt this to your needs
WHILE 1 = 1
BEGIN
BEGIN TRANSACTION
INSERT INTO #TempTable (..., ...)
SELECT ..., ...
FROM Source
ORDER BY ..., ... -- Must be a combination that has no duplicates
IF @@ROWCOUNT = 0 BREAK
DELETE FROM Source
ORDER BY ..., ... -- Same column combination as before
-- The order by ensures that the same (max 10000) rows get deleted that
-- were just copied into the #TempTable.
-- An alternative to using order by is to INSERT INTO 10,000 rows "at
-- random" (without ORDER BY) and use EXISTS to delete the same rows
-- from Source.
UPDATE Dest
SET Sales = #TempTable.Sales
FROM Dest
INNER JOIN #TempTable
ON #TempTable.Material = Dest.Material
AND #TempTable.Customer = Dest.Customer
AND #TempTable.Year = Dest.Year
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
INSERT Dest (Material, Customer, Year, Sales)
SELECT Material, Customer, Year, Sales
FROM #TempTable
WHERE NOT EXISTS
(SELECT *
FROM Dest
WHERE #TempTable.Material = Dest.Material
AND #TempTable.Customer = Dest.Customer
AND #TempTable.Year = Dest.Year)
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
-- Other error handling (generate message, log error, etc.)
GOTO Done
END
COMMIT TRANSACTION
END
-- After WHILE is exited through BREAK, a transaction is still open!
COMMIT TRANSACTION
Done:
PRINT 'Done'

Also, is it possible I can make it generic so that I can pass the
source and target table names and can the stored procedure discover
all the key and non-key columns and do the upsert.


It is possible using dynamic SQL, but I recommend strongly against it. It
does save you some copy, change, paste work when making your application,
but it will probably cost you lots more work in the long run. If I have to
do something like this, I'd prefer to have seperate "upsert" procedures
for each table that needs this functionality. Once you got one working
procedure, it's easy to make more: use copy and paste, change the names
(using find and replace), proofread and test and you're set.

To read more about dynamic SQL: http://www.sommarskog.se/dynamic_sql.html.

Best, Hugo
--

(Remove _NO_ and _SPAM_ to get my e-mail address)
Jul 20 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: newbie_mw | last post by:
Seems my post was buried in more cries for help :-) I will try again. It's probably a very novice question so please take a look! Thanks!...
16
by: robert | last post by:
been ruminating on the question (mostly in a 390/v7 context) of whether, and if so when, a row update becomes an insert/delete. i assume that there is a threshold on the number of columns of the...
10
by: Mike | last post by:
I know this sounds strange but I am at a loss. I am calling a simple funtion that opens a connection to a SQL Server 2000 database and executes an Insert Statement. private void...
1
by: Scott Emick | last post by:
I have the following datatables which are related: Transaction TransactionId-Sequence Orders OrderDetails when I process a daTransaction.update(dtTransaction)...
1
by: glenn | last post by:
Hi folks, I am using an Access database, VB.NET and ADO.NET working with a DataGrid control. MY datagrid table has both a date_sent and a date_ans field. When I Insert a record in my SQL...
3
by: rhaazy | last post by:
Using ms sql 2000 I have 2 tables. I have a table which has information regarding a computer scan. Each record in this table has a column called MAC which is the unique ID for each Scan. The...
3
by: MATTXtwo | last post by:
ALTER PROCEDURE . ( @user_id varchar(8), @pwd varchar(12) ) AS IF EXISTS(SELECT Personel_No From TblUser_ID where Personel_No = @user_id) BEGIN IF EXISTS(SELECT Password From...
2
by: ksenthilbabu | last post by:
Hey All, I am using MSSQL -2005 with VB6. I have created a master table tblCompany and detail Table tblDetail having foreign key relationship. When i try to insert a value within a TRANSACTION I...
5
Privesh Baliper
by: Privesh Baliper | last post by:
Hi I have two tables with the same structur: called DISPLAYLOAYOUT and DISPLAYLAOUT1 : CREATE TABLE CARDBA.DISPLAYLAYOUT - DL ( AREACODE VARCHAR2(5 BYTE) NOT NULL, ...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.