Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 INSERT INTO or UPDATE

Author  Topic 

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 08:30:35
I have several scenarios would I have a large group of data (such as customer demograhpics). These demopgraphics are not in a dataset. Each field is individual and I want to be able to take all the information and if it is a change to UPDATE the demographics table and if it is a new demographic not already in the table for that customer to do an INSERT INTO.

Does anyone have any suggestions on how to do this?

madhivanan
Premature Yak Congratulator

22864 Posts

Posted - 2006-01-25 : 08:42:24
One approach is

Update query

If @@RowCount=0
Insert Query


Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2006-01-25 : 08:47:03
Are ... the missing UPSERT command that is sorely needed in SQL!!

Kristen
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 08:52:41
My problem is that the fields I am passing to the procedure are dynamic.

One time I can have 5 records I need UDPATEd for the same ID and 4 records that need INSERTed for that same ID. And another time I might have 3 for UPDATE and 14 for INSERT.

I could always loop through one record at a time, but that would probably be a huge performance hit and I'm trying to find an easier/better way.
Go to Top of Page

madhivanan
Premature Yak Congratulator

22864 Posts

Posted - 2006-01-25 : 08:55:58
>>Are ... the missing UPSERT command that is sorely needed in SQL!!

Kristen, Which RDBMS supports UPSERT?

Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2006-01-25 : 08:57:54
Madhi, you're taking things too seriously. It was a joke ...
Go to Top of Page

ditch
Master Smack Fu Yak Hacker

1466 Posts

Posted - 2006-01-25 : 08:58:53
Well looks like you have to do it in 2 seperate commands then - one to update existing records and the other to insert new rows.



Duane.
Go to Top of Page

madhivanan
Premature Yak Congratulator

22864 Posts

Posted - 2006-01-25 : 09:02:03
quote:
Originally posted by Kristen

Madhi, you're taking things too seriously. It was a joke ...




Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 09:03:33
ditch,

I realize that. What I was planning on doing was inserting all the data into a temporary table and then determining which rows needed UPDATEd and which need INSERTed, but I'm not sure if there is a way to do this with out looping one row at a time.

Is there a query or sequence of queries I can use to compare the temporary table to the live table and then UPDATE or INSERT the rows as needed?
Go to Top of Page

ditch
Master Smack Fu Yak Hacker

1466 Posts

Posted - 2006-01-25 : 09:13:31
You should possibly look at doing it without temp tables.

ie to insert rows that dont exist in the table you can do something like this.
insert into existing_table
select a.*
from newdata_table a
where not exists (select b.* from existing_table where a.id = b.id)


Duane.
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 09:18:15
I don't see the advantage to creating a permanent table when I just need the data temporarily?
Go to Top of Page

ditch
Master Smack Fu Yak Hacker

1466 Posts

Posted - 2006-01-25 : 09:21:23
no - I'm not saying a permanent table is needed - I am assuming that you have data in one table (newdata_table) which is used to update or insert into your main table (existing_table) or am I missing something?


Duane.
Go to Top of Page

mwjdavidson
Aged Yak Warrior

735 Posts

Posted - 2006-01-25 : 09:40:37
As ever, it would be useful to post some DDL for both your destination and source table(s) (if appropriate) as it's not entirely clear what's going on. It sounds as though you're receiving a number of different feeds (one per field?) each of which associates a customer with a particular piece of demographic information. Am I right in thinking your source is not an RDBMS (
quote:
These demopgraphics are not in a dataset
)? Or am I completely wide of the mark here!?

Mark
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 09:51:32
You are correct. The data source is a web form. I was planning on looping all the textboxes and comboboxes from the web form and creating an SQL statement to insert the values into a temporary table. Then using that temporary table to update or insert new rows into the permanent table.
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 12:51:55
Here is a code listing of what I am trying to do with the UPDATE half of the problem. If you notice towards the bottom I created a check to update and add to the usage log. It seems silly that I would now have to repeat that large block of code for every demographic

http://www.PasteHere.com/?rbsmkl

In the near future I will need create a similiar stored procedure that will also allow me to INSERT fields that don't exist. This current example is all UPDATE.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2006-01-25 : 15:45:55
If you put the data into a temporary table can't you just JOIN it to the main table in two statements:

1) Where PK columns match then do an UPDATE
2) Where PK column does not exist in Master Table (i.e. needs OUTER JOIN) do an INSERT?

Kristen
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 15:55:33
I have to compare the values of waht is in the primary table with what is in the temporary table.

I am only updating them if they are different. I do this because I only wish to place in my usage log table entries that have changed.
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2006-01-25 : 16:39:55
quote:
Originally posted by Billkamm

Here is a code listing of what I am trying to do with the UPDATE half of the problem. If you notice towards the bottom I created a check to update and add to the usage log. It seems silly that I would now have to repeat that large block of code for every demographic

http://www.PasteHere.com/?rbsmkl

In the near future I will need create a similiar stored procedure that will also allow me to INSERT fields that don't exist. This current example is all UPDATE.


If you want us to look at code, it's better to just paste it here into a code block to make it readable.

I usually will not click on a link like that. I don't know about other people, but I doubt if I'm the only one that feels that way.




CODO ERGO SUM
Go to Top of Page

Billkamm
Posting Yak Master

124 Posts

Posted - 2006-01-25 : 16:48:17
I normally do paste the code in here, but it was large amount of code, so I did that link instead.

Here is the updated code. The problem I ran into here is that the EXEC() statement is trying to access out of scope varaiables and I don't want to have to pass every parameter each iteration through the loop


-- Will update all the demographics fields in tblDemographics
CREATE PROCEDURE dbo.usp_UpdateDemographicsTable
(
-- The user ID is required, so it can be added to the usage log
@pkUserID int,

-- Use the application number or broker ID to lookup the demo ID
@AppNumber int,
@BrokerID int,

-- Pass in all the demographics details
@BrokerName varchar(100),
@BrokerDbaNames varchar(100),
@PrimaryContact varchar(20),
@PhoneNumber varchar(25),
@FaxNumber varchar(25),
@EmailAddress varchar(255),
@Address varchar(250),
@City varchar(50),
@fkStateId int,
@Zip char(5),
@fkTerritoryId int,
@fkAssignAcctExecID int,
@Website varchar(255),
@TaxIdNumber varchar(11)
)
AS

SET NOCOUNT ON

BEGIN TRANSACTION;

-- Used for parsing all the column names during the update
DECLARE @column_list AS varchar(250);
DECLARE @parsing_list AS varchar(250);
DECLARE @current_column AS varchar(25);
DECLARE @find_comma AS int;

-- Createa list of all the demographics fields
SELECT @column_list = "BrokerName, BrokerDbaNames, PrimaryContact, PhoneNumber, "
+ "FaxNumber, EmailAddress, Address, City, fkStateId, Zip, fkTerritoryId, "
+ "fkAssignAcctExecID, Website, TaxIdNumber";

-- Pull the demographics ID for this application or broker profile
DECLARE @demoID As int;

IF @AppNumber IS NOT NULL
BEGIN
SELECT @demoID = fkDemoID FROM tblApplications WHERE pkApplicationNumber = @AppNumber;
END
ELSE IF @BrokerID IS NOT NULL
BEGIN
SELECT @demoID = fkDemoID FROM tblBrokers WHERE pkBrokerID = @BrokerID;
END
ELSE
BEGIN
RAISERROR 50000 'No Application number or Broker Profile Number was specified';
RETURN;
END

-- Loop through all the column names
SELECT @parsing_list = @column_list;

WHILE @parsing_list IS NOT NULL
BEGIN
-- Retrieve the next column name
SELECT @find_comma = PATINDEX('%,%', @parsing_list);
IF @find_comma <> 0
BEGIN
-- Pull the column from the list
SELECT @current_column = SUBSTRING(@parsing_list, 1,(@find_comma - 1));

-- Remove the column from the list
SELECT @parsing_list = dbo.Trim(SUBSTRING(@parsing_list, (@find_comma + 1), 250));
END
ELSE
BEGIN
SELECT @current_column = @parsing_list;
SELECT @parsing_list = NULL;
END

-- If the demographics entry has changed update it in the table and add an entry to the usage log
EXEC('
IF @' + @current_column + ' <> (SELECT ' + @current_column + ' FROM tblDemographics WHERE pkDemoId = @demoID)
BEGIN
-- Add an entry to the usage log for either the application or broker ID
INSERT INTO tblUsageLog
(
fkApplicationNumber,
fkBrokerID,
DateTimeOfAction,
fkUserID,
Description
)
Values
(
@AppNumber,
@BrokerID,
GetDate(),
@pkUserID,
''Changed ' + @current_column + ' from '' + (SELECT ' + @current_column + ' FROM tblDemographics WHERE pkDemoId = @demoID) + '' to '' + @' + @current_column + '
);

-- Update the values into the table
UPDATE tblDemographics
SET
' + @current_column + ' = @' + @current_column + ',
WHERE pkDemoId = @demoID;
END
')
END

-- Check for errors before committing the transaction
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION;
RETURN -1;
END
ELSE
BEGIN
COMMIT TRANSACTION
END

GO
Go to Top of Page

Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)

7020 Posts

Posted - 2006-01-25 : 18:56:42
I guess I don't see the point of the loop. You could just SELECT the current values from tblDemographics, and then do a single UPDATE to tblDemographics and a single INSERT into tblUsageLog from a SELECT .. UNION ALL where you send in one row for each column that changed. There is no need for Dynamic SQL at all.

Also, the UPDATE to tblDemographics that you have in your code will not work, unless you change it to Dynamic SQL.



-- Get current values
select
@cur_BrokerName = BrokerName,
@cur_BrokerDbaNames = BrokerDbaNames
... and so on...
from
tblDemographics
where
pkDemoId = @demoID


-- update the row
update a
set
BrokerName =
case
when @BrokerName is not null and
@BrokerName <> a.BrokerName
then @BrokerName
else a.BrokerName
end,
BrokerDbaNames =
case
when @BrokerDbaNames is not null and
@BrokerDbaNames <> a.BrokerDbaNames
then @BrokerDbaNames
else a.BrokerDbaNames
end,
... and so on...
from
tblDemographics a
where
a.pkDemoId = @demoID


-- Log changes
INSERT INTO tblUsageLog
(
fkApplicationNumber,
fkBrokerID,
DateTimeOfAction,
fkUserID,
Description
)
select
@AppNumber,
@BrokerID,
GetDate(),
@pkUserID,
a.Desc
from
(
select Desc =
'Changed BrokerName from '+
@cur_BrokerName+' to '+
@BrokerName
where
@BrokerName is not null and
@BrokerName <> @cur_BrokerName
union all
select Desc =
'Changed BrokerDbaNames from '+
@cur_BrokerDbaNames+' to '+
@BrokerDbaNames
where
@BrokerDbaNames is not null and
@BrokerDbaNames <> @cur_BrokerDbaNames
union all
... and so on...

) a





CODO ERGO SUM
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2006-01-26 : 00:48:27
"I usually will not click on a link like that. I don't know about other people, but I doubt if I'm the only one that feels that way"

Although I'm sure that Billkamm's intention was good I too didn't click it (and don't click "ShortLink.com" URLs)

"but it was large amount of code, so I did that link instead"

Nah! Don't worry about that ...

You could perhaps replace

IF @AppNumber IS NOT NULL
BEGIN
SELECT @demoID = fkDemoID FROM tblApplications WHERE pkApplicationNumber = @AppNumber;
END
ELSE IF @BrokerID IS NOT NULL
BEGIN
SELECT @demoID = fkDemoID FROM tblBrokers WHERE pkBrokerID = @BrokerID;
END
ELSE
BEGIN
RAISERROR 50000 'No Application number or Broker Profile Number was specified';
RETURN;
END

with

IF @AppNumber IS NOT NULL
BEGIN
SELECT @demoID = fkDemoID
FROM dbo.tblApplications
WHERE (@AppNumber IS NULL OR pkApplicationNumber = @AppNumber)
AND (@BrokerID IS NULL OR pkBrokerID = @BrokerID)
IF @@ROWCOUNT = 0 -- Bit naughty, this is "No rows found" rather than "No parameters provided" !!
BEGIN
RAISERROR 50000 'No Application number or Broker Profile Number was specified';
RETURN;
END

(Note that explicitly naming the owner ("dbo.") will help the query planner use the cache more often)

We do UpSerts like this:

UPDATE D
SET
[MyColumn1] = S.[MyColumn1],
[MyStringColumn2] = S.[MyStringColumn2],
...
FROM dbo.MyDestinationTable AS D
JOIN dbo.MySourceTable AS S
ON D.[MyPKColumn] = S.[MyPKColumn]

WHERE
(
(D.[MyColumn1] <> S.[MyColumn1]
OR (D.[MyColumn1] IS NULL AND S.[MyColumn1] IS NOT NULL)
OR (D.[MyColumn1] IS NOT NULL AND S.[MyColumn1] IS NULL))
OR (D.[MyStringColumn2] COLLATE Latin1_General_BIN <> S.[MyStringColumn2]
OR (D.[MyStringColumn2] IS NULL AND S.[MyStringColumn2] IS NOT NULL)
OR (D.[MyStringColumn2] IS NOT NULL AND S.[MyStringColumn2] IS NULL))
)

INSERT INTO dbo.MyDestinationTable
(
[MyPKColumn],
[MyColumn1],
[MyStringColumn2],
...
)
SELECT
[MyPKColumn] = MyPKColumn,
[MyColumn1] = MyColumn1,
[MyStringColumn2] = MyStringColumn2,
...
FROM dbo.MySourceTable S
WHERE NOT EXISTS
(
SELECT *
FROM dbo.MyDestinationTable D
WHERE
D.[MyPKColumn] = S.[MyPKColumn]
)
ORDER BY S.MyPKColumn

Kristen
Go to Top of Page
    Next Page

- Advertisement -