SQL Server Merge WHEN NOT MATCHED clause customizations - sql

When merge clause is used in SQL Server, I need to insert a row when it is not available. This is what I have tried:
drop table test;
create table test (col1 int, col2 varchar(20));
insert into test values(1, 'aaa');
insert into test values(2, 'bbb');
insert into test values(3, 'ccc');
--insert into test values(4, 'eee');
merge test as target
using (SELECT * from test where col1=4) as source
on (target.col1 = source.col1)
when matched then
update set target.col2='ddd'
when not matched by target then
insert values (4, 'ddd');
This updates when upon matching but fails to insert. I have got two questions:
Is there a way to insert upon not matching in the above case?
Can I customize the not matching criteria to raise an error?
Thanks.

The merge works, it's just that your source (SELECT * from test where col1=4) is empty. There is no such row.
You can raise an error using this hack. For example:
when not matched by target then
insert values (0/0 /*ASSERT*/, NULL);

Related

Can SQL before insert triggers access the values of an INSERT statement? [duplicate]

I am trying to create a trigger in mysql that will insert in to another table when an insert on a table occurs.
CREATE TRIGGER addCardForNewUser AFTER INSERT ON swiped.Users
FOR EACH ROW
BEGIN
INSERT INTO swiped.Card (userid) VALUES (get value from original insert here);
END
In the values part of the insert statement how would i get a value from the original insert to use here?
Thanks
You can use those values with new.columnname. If the name of the column is userid too, then you can use:
CREATE TRIGGER addCardForNewUser AFTER INSERT ON swiped.Users
FOR EACH ROW
BEGIN
INSERT INTO swiped.Card (userid) VALUES (new.userid);
END
From the official documentation:
Within the trigger body, the OLD and NEW keywords enable you to access
columns in the rows affected by a trigger. OLD and NEW are MySQL
extensions to triggers; they are not case sensitive.
In an INSERT trigger, only NEW.col_name can be used

Can you make inserting by Id optional?

I want to be able to insert something into my table at a specific ID, so I turned IDENTITY_INSERT on for the table. However, if I just want the auto increment to handle the ID, this error appears:
"Explicit value must be specified for identity column in table
'TsiList' either when IDENTITY_INSERT is set to ON or when a
replication user is inserting into a NOT FOR REPLICATION identity
column."
Is there a way to make the queries
INSERT INTO table (ID, something_else) VALUES (15, 'foo');
and
INSERT INTO table (something_else) VALUES ('foo');
work at the same time?
You can't do it without switching identity_insert on and off as required in between running each query.
Each version will only work when identity_insert is set to the relevant value within the session in which the query is being executed.
For example:
SET IDENTITY_INSERT TsiList ON;
INSERT INTO TsiList (ID, something_else) VALUES (15, 'foo');
SET IDENTITY_INSERT TsiList OFF;
INSERT INTO TsiList (something_else) VALUES ('foo');

Advance Replace in insert scripts

I have below 2 insert statements which i took the export from sql developer from dev environment. I have delete those records from dev afterwards. Now i want to run this insert statement again in dev because those are my back up but i am getting error as virtual column which is ORD_DAYID cannot be used inside insert script. So i want to exclude this column and also the respective values using replace function or any tools which i dont know. I didnt know previously that i have virtual column for this table. I would like to know is there any tool or function where i can select ORD_DAYID and also the respective values get selected and then i can delete those and then i can be able to run this insert statement again in test enviornment.
P.S i have mentioned only 2 sample insert statements but there are 1000 insert statements. So its very difficult to manually delete this ORD_DAYID from this insert statements with respective values.
Insert into test_ord (IS_GRP,ORD_DAYID,REF_CAMPA_CODE) values (1,20150813,null);
Insert into test_ord (IS_GRP,ORD_DAYID,REF_CAMPA_CODE) values (1,20150828,null);
You can edit your INSERT statements using regular expressions, in an editor such as Notepad++.
So to change this ...
Insert into test_ord (IS_GRP,ORD_DAYID,REF_CAMPA_CODE) values (1,20150813,null);
... into this ...
Insert into test_ord (IS_GRP,REF_CAMPA_CODE) values (1,null);
You need a search pattern of:
Insert into test_ord \(IS_GRP,ORD_DAYID,REF_CAMPA_CODE\) values \(([0-9]+),([0-9]+),null\);
and a replace pattern of:
Insert into test_ord \(IS_GRP,REF_CAMPA_CODE\) values \(\1,null\);
Obviously you will need to refine the search pattern to cater for all the different values of IS_GRP, and REF_CAMPA_CODE in your 1000 statements.
" is there any way where we can count the place of column and value and replace it with null"
No. The snag with virtual columns is that they cannot be referenced in INSERT or UPDATE statements. So you need to totally exclude it from the projection.
"i am not able to find those option in notepad++"
Really? Search and replace is not an exotic option:
From the menu: Search > Find > Replace [tab] (or [ctrl]+h)
As the search mode select the regular expression radio button
create an auxiliary table without virtual columns.
Restore your data to this auxiliary table.
Transfer the data from the auxiliary table to the original table.
-- this is your table
create table mytab(A number, b number, s as (a+b));
--fill it with data
insert into mytab(a,b) values(1,1);
insert into mytab(a,b) values(1,2);
insert into mytab(a,b) values(2,1);
insert into mytab(a,b) values(2,2);
commit;
-- check its content
select * from mytab;
-- now delete the rows
delete from mytab;
commit;
-- restore your data
--------------------
-- create a table similar the table you want to restore
-- but the virtual colums as regular columns.
create table ctas as
select * from mytab where 1!=0;
-- insert your backup data
insert into ctas(a,b,s) values(1,1,2);
insert into ctas(a,b,s) values(1,2,3);
insert into ctas(a,b,s) values(2,1,3);
insert into ctas(a,b,s) values(2,2,4);
commit;
-- transfer the data to the table you want to restore
insert into mytab(a,b) select a,b from ctas;

How to insert autoincrementing id from one table into another in one command (using returning)?

I've attempted the following:
INSERT INTO second_table(id, somethingelse)
VALUES(
(INSERT INTO first_table(post_text) VALUES('a text') RETURNING id),
'abcd123'
);
I know how to do select with 2 query, but I'm trying to avoid any concurrency issue by doing these 2 insertions at once. Above gives me the following error:
ERROR: syntax error at or near "INTO"
LINE 3: (INSERT INTO first_table(post_text) VALUES('a text...
I'm trying to insert auto-incrementing id from first_table into second_table when a row is inserted into first_table.
Use a data modifying CTE:
with first_insert as (
INSERT INTO first_table(post_text)
VALUES('a text')
RETURNING id
)
INSERT INTO second_table(id, somethingelse)
select id, 'abcd123'
from first_insert;
Try creating a trigger to be executed whenever a row is inserted in first table.
something like:
CREATE TRIGGER trigger_name AFTER INSERT OF post_text
ON first_table
[
INSERT INTO second_table(id, somethingelse)
VALUES(
(select id from first_table where post_text='a text'),
'abcd123'
);
];
You need to run below command to off identity column
Set Identity_Insert [TableName] Off

I need insert 2 records in differents tables,

I need to insert 2 records into 2 different tables. The problem is that the two records will be with the same Id.
For example :
I have my Mannto table, with its IdMan and oters fields. I also have my Service table, with its IdServ.
What can I do to make this one equal? I am using Postgre. The Id of the Mannto table is serial and I need to use that one as a Foreign key in the Service table
I tried the following, but it does not work:
Insert into Mannto ( idMan, field 1 field2 ...etc)
values ( default, 'f1', 'f2'...etc)
Insert into Service ( idServ, fkMannto, field1...etc)
values (default, (in this part I need the same ManntoId called idMan), 'f1')
Thank you for any help you can provide!
INSERT INTO Mannto ( field1, field2 ...etc) VALUES ( 'f1', 'f2'...etc)
RETURNING idMan;
http://www.postgresql.org/docs/current/static/sql-insert.html
When field idMan uses a sequence to create a new value, you can refer to this value in the next INSERT using CURRVAL():
BEGIN; -- start transaction
INSERT INTO Mannto ( idMan, field 1 field2 ...etc)
VALUES ( default, 'f1', 'f2'...etc);
INSERT INTO Service ( idServ, fkMannto, field1...etc)
VALUES (default, currval('name_of_the_sequence') , 'f1');
COMMIT; -- commit both inserts
Maybe it's not the best solution but you could use a trigger.
CREATE TRIGGER MannToTrigger
AFTER INSERT OR UPDATE OR DELETE ON MannTo
FOR EACH ROW EXECUTE PROCEDURE insertService();
Fetch your MannTo inserted last code and throw the procedure after each insert.