I have a problem with my database based on HSQLDB (OpenOffice 3.3.0). I am trying to create SQL command that will select rows with specified columns from source table and copy it across to the destination table keeping in mind that if record does not exist in destination table, it should get created and if it does exist it should get updated. Please note that I am using quite old HSQLDB engine which does not support MERGE command.
Thanks.
With the old HSQLDB 1.8, you need to perform an INSERT and an UPDATE.
INSERT INTO dest (SELECT * FROM SOURCE WHERE <your condition> EXCEPT (SELECT * FROM source JOIN dest ON source.id = dest.id WHERE <your condition>));
UPDATE dest SET (col1, col2) = (SELECT coln, colm FROM source WHERE source.id = dest.id) WHERE <your condition>
Related
I use SQL Server 2014.
In my procedure, I have a MERGE statement and I have a question about it.
My MERGE statement has simple following structure:
MERGE dbo.T1 AS tgt
USING (SELECT ...) AS src ON ...
WHEN MATCHED THEN
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...
OUTPUT inserted.MyColumn
INTO #NewTable (MyColumnValue);
Just like how it populates a table for all inserts, I also need it to populate another table for all updates too.
Is is possible, and if yes then would you please let me know how?
No, it's not possible to direct the results to two tables. See this question.
You can make the table wider and output both the inserted and deleted columns on the same row:
MERGE dbo.T1 AS tgt
USING (SELECT ...) AS src ON ...
WHEN MATCHED THEN
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...
OUTPUT $action, inserted.col1, inserted.col2, deleted.col1, deleted.col2
INTO #NewTable (action, inserted_col1, inserted_col2, deleted_col1, deleted_col2);
Then you can split #NewTable however you want.
I am loading CSV files to Redshift daily. To handle duplicates i am loading the files to staging table and then using Update or Insert scripts based on key columns to load to the target table. Recently i found duplicate data in the target table unexpectedly.
I double checked my script and don't see any reason for having duplicates. Below are the Update and Insert script formats that i am using.
For Inserting:
Insert into target (key1, key2, col3, col4)
Select key1, key2, col3, col4
From stage s where not exists (select 1 from target t
where s.key1 = t.key1 and)
s.key2 = t.key2);
And for update:
Update target Set
key1=s.key1, key2=s.key2, col3=s.col3, col4=s.col4
From stage s where target.key1=s.key1 and target.key2=s.key2;
Any help is appreciated.
I ran into this too. The problem was in the insert...select... where the select itself produced duplicates. One solution for us was to use a cursor (outside of Redshift) to run the select and insert one record at a time, but this proved to have performance issues. Instead we now check for duplicates with an initial select
select key1,key2 from stage group by key1,key2 having count(*) > 1;
and stop the process if records are returned.
I'm importing data from one database table to another with different structure and I'm using this code:
UPDATE BD1.dbo.Table1
SET C2=t2.C2
from BD2.dbo.Table2 as t2
WHERE c1=t2.c1 collate SQL_Latin1_General_CP1_CI_AI
IF ##ROWCOUNT=0 INSERT INTO BD1.dbo.Table1 (c1,c2)
select t2.c1, t2.c2 From BD2.dbo.Table2 as t2
If I don't have any matches between BD1 and BD2 this works fine, but if I do, the command just updates the existing fields. I want to update the existing fields and create the new ones (?!).
I believe the problem is in the ##rowcount=0, but I have a where condition before it should respect record by record, doesn't it?
The merge statement was written for just this operation. It is called an UPSERT = update the record if it exists or insert it if it does not.
Since, I do not have your schema, I can not test the snippet below. But here is a TSQL sample that might work for you.
-- UPSERT from staging to production
MERGE INTO
BD1.dbo.Table1 AS Target
USING
(SELECT C1, C2 FROM BD2.dbo.Table2) AS Source (C1, C2)
ON
Target.C1 = Source.C1 collate SQL_Latin1_General_CP1_CI_AI
WHEN MATCHED THEN
UPDATE SET Target.C2 = Source.C2
WHEN NOT MATCHED BY TARGET THEN
INSERT (C1, C2) VALUES (Source.C1, Source.C2)
;
I have a table (in informix ) which stores two columns :empId and status (Y/N). There are some other scripts which, when run, update the status of these employeeIDs based on certain conditions.
The task at hand is , a user provides a path to a file containing employee-IDs. I have a script which then looks at this file and does a "load from user_supplied_file insert into employeeStatusTable".
All the employeeIDs mentioned in this file are to be inserted in this table with the status 'N'. Th real issue is the user-supplied file may contains an employeeId that is already present in the table with the status updated to 'Y' (by some other script or job). In this case, the existing entry should get overwritten. In short, the entry in the table should read "empId", "N".
Is there any way to acheive this? Thanks in advance.
As far I know , the LOAD statement is limited to use together of INSERT statement.
I pretty sure there a lot of ways to do this , I will suggest two way:
In both cases, is supported only for database version >= 11.50 and have certain limitations like:
The Merge works only if the two tables have 1 to 1 relationship
The external table is limited to Database Server file system, not will access anything on client machine
SUGGESTION 1
Load into a temporary table and then use the MERGE statement.
create temp table tp01 ( cols.... ) with no log ;
load from xyz.txt insert into tp01 ;
merge into destTable as A
using tp01 as B
ON A.empID = B.empID
WHEN MATCHED THEN UPDATE SET status = 'N'
WHEN NOT MATCHED THEN INSERT (empid, status) values ( b.empid, 'N');
drop table tp01;
SUGGESTION 2
Create a external table to you TXT file and then just use the MERGE or UPDATE using this table when needed.
create external table ex01 .... using ( datafile('file:/tmp/your.txt'), delimited ...);
merge into destTable as A
using ex01 as B
ON A.empID = B.empID
WHEN MATCHED THEN UPDATE SET status = 'N'
WHEN NOT MATCHED THEN INSERT (empid, status) values ( b.empid, 'N');
I need to insert the data in a csv file in to a temporary table and insert some data for the corresponding id value in another table. I have created and inserted the data in to the csv file. For all the records in the csv file how can I loop through and insert dome data for the corresponding record in the other table.
CREATE TABLE #tbcompanies
(ID INT)
GO
BULK
INSERT #tbcompanies
FROM 'd:\ids.csv'
WITH
(
ROWTERMINATOR = '\n'
)
select * from #tbcompanies
drop table #tbcompanies
Assuming both tables have an ID column, you could update the other table like:
update ot
set col1 = tmp.col1
. col2 = tmp.col2
from #tbcompanies tmp
join OtherTable ot
on ot.ID = tmp.ID
If in addition to updating, you'd like to insert rows that do not exist, consider the merge statement:
; merge OtherTable as target
using #tmpcompanies as source
on target.id = source.id
when not matched by target then
insert (id, col1, col2) values (source.id, source.col1, source.col2)
when matched then
update set col1 = source.col1, col2 = source.col2;
You don't need to loop through anything, since you use SQL Server 2008 and this version supports the MERGE statement.
Have a look here.
Or simply use update with a from clause and join the two tables.
If it's upsert functionality you need, I strongly recommend the Merge function.
pseudo code
merge TargetTableName target
using #tbcompanies tmp on tmp.idfield=target.idfield
when matched then update......
when not matched then insert...........