Problems inserting new data into SQL Server table - sql

I am trying to do an if else insert into one table from another (a table type).
I am having problems where basically the first time the script runs it adds all data into the table OK but then if something is added to the source data afterwards, it does not add the new record and I don't know why.
I can't include the exact code but it looks like this...
UPDATE CUSTOMER
Set Target.Desc = Source.Desc
From #source source
WHERE Target.AccountNumber = Source.AccountNumber
IF ##ROWCOUNT=0
INSERT INTO CUSTOMER(AccountNumber, Desc)
SELECT Source.AccountNumber, Source.Desc
FROM #Source Source
I have also tried a traditional if else insert but it had the same results.
Can you see anything wrong that might be stopping the newly added records from being inserted?

Your current code will only work correctly if #source contains either all existing or all new rows.
You can use MERGE when this is not the case
MERGE CUSTOMER AS target
USING #source AS source
ON ( target.AccountNumber = source.AccountNumber )
WHEN MATCHED THEN
UPDATE SET [Desc] = source.[Desc]
WHEN NOT MATCHED THEN
INSERT (AccountNumber, [Desc])
VALUES (AccountNumber, [Desc]);

How about doing this instead of using ##ROWCOUNT
-- update existing customers
UPDATE c
SET c.Desc = Source.Desc
FROM #source source
INNER JOIN CUSTOMER c ON c.AccountNumber = Source.AccountNumber
-- insert new customers
INSERT INTO CUSTOMER(AccountNumber, Desc)
SELECT Source.AccountNumber, Source.Desc
FROM #Source Source
LEFT JOIN CUSTOMER c ON Source.AccountNumber = c.AccountNumber
WHERE c.AccountNumber IS NULL

-- update all existing rows
update c set
c.Desc = s.Desc
from CUSTOMER c
join #source s on s.AccountNumber=c.AccountNumber
-- insert all missing rows
insert into CUSTOMER (AccountNumber, Desc)
select s.AccountNumber, s.Desc
from #Source s
where not exists(
select *
from CUSTOMER c
where c.AccountNumber=s.AccountNumber
)

The first time, there is no data in your target so ##rowcount is 0.
Next time, the update updates all data and ##rowcount is not 0 and you get no data inserted.
You should not use ##rowcount but do what Andrew suggest: do both UPDATE and INSERT
or MERGE (do both in one statement)

##ROWCOUNT value contains the count of affected rows. the insert statement works only if all the records are new. and it does not go for updation. if any of the record got updated, it would not go for insertion even the source contains new records
If your requirement is to update existing records and Insert New records from source , you can use the below code.
-- update existing Rows
UPDATE CUSTOMER
SET CUSTOMER.Desc = SOURCE.Desc
from #SOURCE Source
WHERE Source.AccountNumber=CUSTOMER.AccountNumber
-- Insert New Data
INSERT INTO CUSTOMER (AccountNumber, Desc)
SELECT s.AccountNumber, s.Desc
FROM #Source Source
WHERE not exists( SELECT 1
FROM CUSTOMER
WHERE CUSTOMER.AccountNumber=Source.AccountNumber)

Related

TSQL: Prevent Nulls update over existing data

I have 2 tables:
Orders (Table I update and want keep existing data, and prevent overwriting with nulls)
WRK_Table (This table is identical to Orders but can not guarantee all columns will have data when running update)
PK column 'Master_Ordernum'
There are many columns in the tables, the WRK_Table will have the PK, but data in other columns can not be counted on.
I want the WRK_Table to update Orders only with actual data and not Nulls.
I was thinking along this line:
UPDATE [Orders]
SET [Status] = CASE WHEN S.[Status] IS NOT NULL THEN S.[Status] END
FROM [WRK_TABLE] S
WHERE [Orders].[Master_Ordernum] = S.[Master_Ordernum]
The existing data in Orders is being updated with nulls
does this help?
update orders set name = work.name
from orders
inner join work on orders.id = work.id and work.Name is not null
Not the same col / table name but you should get the idea
EDIT
Your SQL, NOT TESTED
UPDATE Orders
SET [Status] = WRK_Table.[Status]
FROM [Orders]
inner join WRK_Table on [Orders].[Master_Ordernum] = [WRK_Table].[Master_Ordernum] and WRK_Table.[Status] is not null
If you want to test and undo your data just do something like (assuming you don't have 100s of rows)
begin tran
/* .. SQL THAT UPDATES ... */
select * from orders // review the data
rollback tran // Undo changes
If you're going to use a Case statement, you need to include an else to prevent it from just inserting that null. Try this - if the work table has a null, let it just overwrite the value with the existing value.
UPDATE [Orders]
SET [Status] = CASE WHEN S.[Status] IS NOT NULL THEN S.[Status] else [Orders].[Status] END
FROM [WRK_TABLE] S
WHERE [Orders].[Master_Ordernum] = S.[Master_Ordernum]
Not sure if you can use
Update my_table set col = ISNULL(#newval,#existingval) where id=#id
https://msdn.microsoft.com/en-us/library/ms184325.aspx

Using a LEFT OUTER JOIN WHERE then updating same data

I have two databases running on MSSQL 2005, SOURCE and DESTINATION, which have the same structure and tables in them.
I'm trying to update data from s to d.
In this example, I'm trying to copy data from s to d using a join and only bringing across entries which aren't already in d.
I'm then trying to update the same records just inserted with vales thus:
INSERT DESTINATION.ITEM_REPLENISH_VENDOR ([ITEM_CODE],[VEND_CODE],[PRIMARY_VENDOR],[PURCHASE_MEASURE],[STD_COST],[LAST_COST],[EOQ],[VENDOR_PART_NO],[LEAD_TIME],[COST])
SELECT s.[ITEM_CODE],s.[VEND_CODE],s.[PRIMARY_VENDOR],s.[PURCHASE_MEASURE],s.[STD_COST],s.[LAST_COST],s.[EOQ],s.[VENDOR_PART_NO],s.[LEAD_TIME], s.[COST] FROM SOURCE.dbo.ITEM_REPLENISH_VENDOR s
LEFT OUTER JOIN DESTINATION.dbo.ITEM_REPLENISH_VENDOR d ON (d.ITEM_CODE = s.ITEM_CODE)
WHERE d.ITEM_CODE IS NULL
UPDATE DESTINATION.dbo.ITEM_REPLENISH_VENDOR
SET VEND_CODE='100004', PRIMARY_VENDOR='T',STD_COST='0',LAST_COST='0',COST='0'
WHERE
My issue is once I reach the second WHERE I don't know how to refer to the data I've just updated. This script is going to run either every day at a set time and I don't want to overwrite that whole column with those values, just the entries that have been inserted on this execution.
It looks like you want the output clause This will let you stash away the inserted values.
-- item_code needs to have the same type as the source table
declare #inserted table (item_code int not null primary key);
insert destination.item_replenish_vendor (
[item_code], [vend_code], [primary_vendor],
[purchase_measure], [std_cost], [last_cost],
[eoq], [vendor_part_no], [lead_time],[cost]
) -- save inserted values
output
inserted.item_code into #inserted
select
s.[item_code], s.[vend_code], s.[primary_vendor],
s.[purchase_measure], s.[std_cost], s.[last_cost],
s.[eoq], s.[vendor_part_no], s.[lead_time], s.[cost]
from
source.dbo.item_replenish_vendor s
left outer join
destination.dbo.item_replenish_vendor d
on d.item_code = s.item_code
where
d.item_code is null;
update
d
set
vend_code = '100004',
primary_vendor = 'T',
std_cost = '0',
last_cost = '0,
cost = '0'
from
destination.dbo.item_replenish_vendor d
inner join
#inserted i
on d.item_code = i.item_code;
In this case, you could just put constant values in the insert statement, instead of doing things in two steps...
In the example you have:
UPDATE DESTINATION.dbo.ITEM_REPLENISH_VENDOR
SET VEND_CODE='100004', PRIMARY_VENDOR='T',STD_COST='0',LAST_COST='0',COST='0'
If your VEND_CODE, PRIMARY_VENDOR, STD_COST, LAST_COST, COST are always going to be a static value, you could just put them into the first query.
INSERT DESTINATION.ITEM_REPLENISH_VENDOR ([ITEM_CODE],[VEND_CODE],[PRIMARY_VENDOR],[PURCHASE_MEASURE],[STD_COST],[LAST_COST],[EOQ],[VENDOR_PART_NO],[LEAD_TIME],[COST])
SELECT s.[ITEM_CODE],'100004','T',s.[PURCHASE_MEASURE],'0','0',s.[EOQ],s.[VENDOR_PART_NO],s.[LEAD_TIME], '0'
FROM SOURCE.dbo.ITEM_REPLENISH_VENDOR s
LEFT OUTER JOIN DESTINATION.dbo.ITEM_REPLENISH_VENDOR d ON (d.ITEM_CODE = s.ITEM_CODE)
WHERE d.ITEM_CODE IS NULL
but if they do need to be calculated after insert, then I agree with Laurence's approach.

How to copy or update from one table to another table

I have two tables. user and user_new
the user contains the old data.
the user_new contains the new data.
I want to sync the user_new to user.
if the data exist in user_new and not exist in user,then insert to user.
if the data exist in user and user_new, then update.(compare with the column id)
what's the fast sql to do it?
This works on any server version -
-- 1) Insert new record
INSERT INTO old_table(id, column)
SELECT n.id, n.column
FROM new_table n
LEFT JOIN old_table o ON n.id = o.id
WHERE o.id IS NULL
-- 2) Update existed record
UPDATE o
SET column = n.column
FROM old_table o
JOIN new_table n ON n.id = o.id
From Sql Server 2008 onwards you can use Merge syntax
MERGE user target
USING user_new source
ON taget.ID = source.ID
WHEN MATCHED THEN
UPDATE
SET target.Column= source.Column1,target.column2=source.column2
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID,Column1,Column2)
VALUES (source.ID,source.column1,source.column2);
or you can use the below query
INSERT INTO user(ID,column1,column2)
SELECT ID,column1,column2 FROM user_new AS source
WHERE NOT EXISTS (SELECT * FROM user WHERE ID = source.ID);
UPDATE target SET ...
FROM user AS target
INNER JOIN user_new AS source
ON target.ID = source.ID;
Sounds like you might need a Merge if you have sql server 2008+.
You can't do insert and update in a single query you have to do in seperate
select * from user where user_id not in (select user_new.user_id from user_new )
this query results the data for insert query similarly u have to update by replacing not in to in

T-SQL Trigger - Updating a Table using a separate table, multi-row insert possible

I'm new to triggers and am working on setting up a trigger to update a table (REQ_L) when a record is inserted there that meets specific parameters. The value to update in REQ_L is pulled from a separate table that has a matching key.
create table REQ_L (item_number varchar(20),
commodity_code varchar(20),
vendor_id varchar(20),
item_source varchar(20));
create table XREF_C (item_number varchar(20),
commodity_code varchar(20),
xref_type varchar(20));
I'd like it for when a record is inserted into REQ_L, if it meets the criteria in the trigger it will be update the COMMODITY_CODE from REQ_L with the COMMODITY_CODE in XREF_C using the ITEM_NUMBER as the key.
No longer locking and switched over to using the inserted tables. The good news is no more deadlock, the bad is that it's still not updating the table. Updated SQL Trigger attempt:
CREATE TRIGGER WBM
ON REQ_L
AFTER INSERT
AS
IF EXISTS (SELECT * FROM inserted WHERE VENDOR_ID = 'W7315'
AND ITEM_SOURCE = 'XML'
AND COMMODITY_CODE NOT LIKE '%-%')
BEGIN
UPDATE REQ_L
SET COMMODITY_CODE = (SELECT distinct CODE_2
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
AND xc.XREF_TYPE = 'WBM')
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
END
GO
Try simplyfing your query structure. I still don't know what CODE_1 and CODE_2 are but this worked for me.
ALTER TRIGGER [dbo].[WBM]
ON [dbo].[REQ_L]
AFTER INSERT
AS
UPDATE REQ_L
SET commodity_code = xc.commodity_code FROM INSERTED i INNER JOIN XREF_C xc ON i.Item_Number=xc.item_number
AND
xc.xref_type = 'WBM'
AND
i.VENDOR_ID = 'W7315'
AND
i.ITEM_SOURCE = 'XML'
AND
i.COMMODITY_CODE NOT LIKE '%-%'
Remember, IF statements belong in C# and Visual Basic - if you are using them in SQL you are not writing your queries with a dataset mentality. Most of the time that is; sometimes they can't be avoided.
I agree with the general comments above, but I'm thinking the logic your using looks dodgy. You have:
UPDATE REQ_L
SET COMMODITY_CODE = (SELECT distinct CODE_2
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
AND xc.XREF_TYPE = 'WBM')
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
Well I may be wrong, but I can't help thinking that the table you're updating should appear in the from clause of the statement.
How about this:
UPDATE rl
SET Commodity_Code = x.Code_2
FROM Req_L rl
INNER JOIN Inserted i ON --limit the join clause to the cols that have been inserted
rl.item_number = i.item_number and
rl.commodity_code = i.commodity_code and
rl.vendor_id = i.vendor_id and
rl.item_source = i.item_source
INNER JOIN XREF_C x ON L.item_number = x.item_number
WHERE x.xref_type = 'WBM'

Copy values from one table to another in SQL

I have 2 tables. I need to update all rows of table 1 with the values in specific columns from table 2. They have the same structure.
UPDATE #TempTable
SET [MyColumn] =
(
SELECT [MyColumn]
FROM
[udf_AggregateIDs] (#YearId) AS [af]
INNER JOIN [MyForm] ON
(
[af].[FormID] = [MyForm].[FormID] AND
[af].[FormID] = #MyFormId
)
WHERE [Description] = [MyForm].[Description]
)
I get an error saying Subquery returned more than 1 value. I only added the where clause in because i thought sql is struggling to match the rows, but both tables have the same rows.
It should return multiple values because i'm trying to copy across all rows for MyColumn from the one table to the other.
Ideas?
is Description unique ?
select [Description], count(*) from [MyForm] group by [Description] having count(*)>1
You don't need a sub query..just join the tables..
same type of question has been answered here. Hope it helps.
Have to guess here because your query isn't self-documenting. Does MyColumn come from the function? Does #TempTable have a description column? Who knows, because you didn't prefix them with an alias? Try this. You may have to adjust since you know your schema and we don't.
UPDATE t
SET [MyColumn] = func.MyColumn -- have to guess here
FROM dbo.[udf_AggregateIDs] (#YearId) AS func
INNER JOIN dbo.MyForm AS f
ON func.FormID = f.FormID
INNER JOIN #TempTable AS t
ON t.Description = f.Description -- guessing here also
WHERE f.FormID = #MyFormID;