Insert into a Informix table or update if exists - sql

I want to add a row to an Informix database table, but when a row exists with the same unique key I want to update the row.
I have found a solution for MySQL here which is as follows but I need it for Informix:
INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name="A", age=19

You probably should use the MERGE statement.
Given a suitable table:
create table table (id serial not null primary key, name varchar(20) not null, age integer not null);
this SQL works:
MERGE INTO table AS dst
USING (SELECT 1 AS id, 'A' AS name, 19 AS age
FROM sysmaster:'informix'.sysdual
) AS src
ON dst.id = src.id
WHEN NOT MATCHED THEN INSERT (dst.id, dst.name, dst.age)
VALUES (src.id, src.name, src.age)
WHEN MATCHED THEN UPDATE SET dst.name = src.name, dst.age = src.age
Informix has interesting rules allowing the use of keywords as identifiers without needing double quotes (indeed, unless you have DELIMIDENT set in the environment, double quotes are simply an alternative to single quotes around strings).

You can try the same behavior using the MERGE statement:
Example, creation of the target table:
CREATE TABLE target
(
id SERIAL PRIMARY KEY CONSTRAINT pk_tst,
name CHAR(1),
age SMALLINT
);
Create a temporary source table and insert the record you want:
CREATE TEMP TABLE source
(
id INT,
name CHAR(1),
age SMALLINT
) WITH NO LOG;
INSERT INTO source (id, name, age) VALUES (1, 'A', 19);
The MERGE would be:
MERGE INTO target AS t
USING source AS s ON t.id = s.id
WHEN MATCHED THEN
UPDATE
SET t.name = s.name, t.age = s.age
WHEN NOT MATCHED THEN
INSERT (id, name, age)
VALUES (s.id, s.name, s.age);
You'll see that the record was inserted then you can:
UPDATE source
SET age = 20
WHERE id = 1;
And test the MERGE again.
Another way to do it is create a stored procedure, basically you will do the INSERT statement and check the SQL error code, if it's -100 you go for the UPDATE.
Something like:
CREATE PROCEDURE sp_insrt_target(v_id INT, v_name CHAR(1), v_age SMALLINT)
ON EXCEPTION IN (-100)
UPDATE target
SET name = v_name, age = v_age
WHERE id = v_id;
END EXCEPTION
INSERT INTO target VALUES (v_id, v_name, v_age);
END PROCEDURE;

Related

Trigger to insert same table after condition is satsified

I want to insert a row if the field 'Rem' is yes. I am using triggers. Here the issue is I want to insert the data in the same table. Could you please let me know if you have come across this scenario?
Example:
create table Table1
(
id int,
name varchar(100),
is_rem varchar(20)
);
create or replace trigger Table1Trigger
after insert
on Table1
for each row
when (new.is_rem ='yes')
begin
insert into Table1 (id, name, is_rem)
values (:new.id, :new.name, :new.is_rem);
end; /
If I am inserting the is_rem as yes, the table should have two rows of the same data.
Below should works in MySQL
create table if not exists Table1 ( id int, name varchar(100), is_rem varchar(20) );
insert into Table1
select new_id as id, new_name as name, new_is_rem as is_rem
from Table2 where new_is_rem = 'yes';

Insert into table from select only when select returns valid rows

I want to insert into table from select statement but it is required that insert only happens when select returns valid rows. If no rows return from select, then no insertion happens.
insert into products (name, type) select 'product_name', type from prototype where id = 1
However, the above sql does insertion even when select returns no rows.
It tries to insert NULL values.
I know the following sql can check if row exists
select exists (select true from prototype where id = 1)
How to write a single SQL to add the above condition to insert to exclude the case ?
You are inserting the wrong way. See the example below, that doesn't insert any row since none matches id = 1:
create table products (
name varchar(10),
type varchar(10)
);
create table prototype (
id int,
name varchar(10),
type varchar(10)
);
insert into prototype (id, name, type) values (5, 'product5', 'type5');
insert into prototype (id, name, type) values (7, 'product7', 'type7');
insert into products (name, type) select name, type from prototype where id = 1
-- no rows were inserted.

Generate ID for duplicate values in sql server

I found following link to assign identical ID to duplicates in SQL server,
my understanding there is no sql server function to automatically generate it rather than using insert and update queries in link attached, is that statement True, if yes, then what would be the trigger if for example someone insert data to MyTable then run insert and update query from link:
Assign identical ID to duplicates in SQL server
INSERT INTO secondTable (word) SELECT distinct word FROM MyTable;
UPDATE MyTable SET ID = (SELECT id from secondTable where MyTable.word = secondTable.word)
thanks,
S
Is this what you want? I can't think of an "automatic" solution that would just increase the Id for new words.
CREATE TABLE MyTable (
Id INT NOT NULL,
Word NVARCHAR(255) NOT NULL
PRIMARY KEY (Id, Word)); -- primary key will make it impossible to have more than one combination of word and id
DECLARE #word NVARCHAR(255) = 'Hello!';
-- Get existing id or calculate a new id
DECLARE #Id INT = (SELECT Id FROM MyTable WHERE Word = #word);
IF(#id IS NULL) SET #Id = (SELECT MAX(Id) + 1 FROM MyTable);
INSERT INTO MyTable (Id, Word)
VALUES (#id, #word)
SELECT * FROM MyTable
If you can't for some reason have id and word as a combined primary key, you may use an unique index to make sure that there is only one combination

Merge with primary key violation

I have a file based import thingy where the users can post files to be imported in the database. New records are inserted and records with an already existing Id are updated.
After posting a file with
ID NAME
5 Silly
they can correct this by posting a new file with
ID NAME
5 Sally
I have a bulk insert (C# windows service) of the file into a bulk table (Sql Server Azure v12). The files can contain millions of rows so I'd like to avoid iterating through rows. After the bulk insert i have a SP that does a merge update / insert and updates already existing rows and inserts new ones.
The problem I've come across is when the users post a new record and a correction of the same record in the same file. I get a PRIMARY KEY VIOLATION on the target table.
Is there a nice way to solve this?
Here's an example:
--drop table #bulk
--drop table #target
create table #bulk(
id int,
name varchar(10)
)
insert into #bulk values (1,'John')
insert into #bulk values (2,'Sally')
insert into #bulk values (3,'Paul')
insert into #bulk values (4,'Gretchen')
insert into #bulk values (5,'Penny')
insert into #bulk values (5,'Peggy')
create table #target(
id int not null,
name varchar(10),
primary key (id))
merge #target as target
using(select id, name from #bulk) as bulktable
on target.id = bulktable.id
when matched then update
set target.name = bulktable.name
when not matched then
insert(id, name) values (bulktable.id, bulktable.name);
This will handle the latest value for name.
You need a new create script for #bulk
CREATE TABLE #bulk
(
row_id int identity(1,1),
id int,
name varchar(10)
)
This is the script you can use with the new bulk table:
;WITH CTE as
(
SELECT
id, name,
row_number() over (partition by id order by row_id desc) rn
FROM #bulk
), CTE2 as
(
SELECT id, name
FROM CTE
WHERE rn = 1
)
MERGE #target as target
USING CTE2 as bulktable
on target.id = bulktable.id
WHEN matched and
not exists(SELECT target.name except SELECT bulktable.name)
-- this will handle null values. Otherwise it could simply have been:
-- matched and target.name <> bulktable.name
THEN update
SET target.name = bulktable.name
WHEN not matched THEN
INSERT(id, name) VALUES (bulktable.id, bulktable.name);

Derby Merge insert not working

I wanted to create a SQL query which is working like INSERT IF NOT EXISTS ELSE UPDATE
I found that Derby is capable of MERGE and i tried to use it to solve my issue.
MERGE INTO test_table a
USING test_table b
ON a.city = 'foo'
WHEN NOT MATCHED THEN INSERT values ( 'foo', '2012-11-11', 'UK')
WHEN MATCHED AND a.modification_date > '1111-11-11' THEN
UPDATE SET a.modification_date = '2012-11-11',
a.city = 'foo1',
a.country = 'US'
The above statement is giving me the following error:
Error code 30000, SQL state 23505: The statement was aborted because it
would have caused a duplicate key value in a unique or primary key
constraint or unique index identified by 'SQL150129144920080' defined on 'test_table'
How ever i can run the following statement:
INSERT INTO test_table values ( 'foo', '2012-11-11', 'UK');
Which is proving that the above city does not exists in the table yet.
My table is contains the following structure:
CREATE TABLE test_table(
city VARCHAR(100) NOT NULL PRIMARY KEY,
modification_date DATE NOT NULL,
country VARCHAR(2) NOT NULL);
Any help or advice is greatly appreciated.
You have missed the following sentence from here
"The unqualified source table name (or its correlation name) may not be the same as the unqualified target table name (or its correlation name)."
that means you cannot use one table as source and target at the same time !
just one example:
we have two schemas: schema1 and schema2
and two tables: schema1.table1 and schema2.table1
--i have to write all details:
create schema schema1;
create table schema1.table1 (
name varchar(255) not null,
id int not null primary key
);
create schema schema2;
create table schema2.table1 (
name varchar(255) not null,
id int not null primary key
);
--suppose we have inserted some entries into schema2.table1
insert into schema2.table1 values
('foo', 1), ('bar', 2);
--and we want just to copy values from schema2.table1 into schema1.table1
--apply MERGE INTO ... INSERT ...
merge into schema1.table1 as tableTarget
using schema2.table1 as tableSrc
on tableTarget.id= tableSrc.id
when matched then
update set tableTarget.name=tableSrc.name
when not matched then
insert(name, id) values (tableSrc.name, tableSrc.id);
--that has to work
You are not joining table a to table b so the query is likely trying to do an insert for every row in table B, assuming table B contains a city field try
MERGE INTO test_table as a
USING test_table b
ON a.city = b.city and a.city = 'foo'
WHEN NOT MATCHED THEN INSERT values ( 'foo', '2012-11-11', 'UK')
WHEN MATCHED AND a.modification_date > '1111-11-11' THEN
UPDATE SET a.modification_date = '2012-11-11',
a.city = 'foo1',
a.country = 'US';