Trigger to insert one record to new rows from another table - sql

I have a small app that inserts data into the database.
I have a something like this
dbo.system.table1(col1, col2, col3) and table2(col1) (table2.col1 is just one single row).
What I want to do is insert the table2.col1 into table1.col3 when a new order is made.
Also the table2.col1 updates twice a day, so every time a new order is made with table1 I need to keep the old table1.col3 changes.
I've tried
CREATE TRIGGER dbo.TR_CHANGES
ON dbo.SYSTEM
AFTER INSERT
AS
UPDATE table1
SET table1.col3 = (SELECT col1
FROM table2
WHERE table1.col3 = table2.col1)
But it ends updating col3 for all rows.

You need to include the Inserted pseudo table into your statement, to find the rows that were actually updated - and I would recommend using proper JOIN syntax instead of those nested subqueries - seems a lot easier to read and understand for me.
So try this:
CREATE TRIGGER dbo.TR_CHANGES
ON dbo.SYSTEM
AFTER INSERT
AS
UPDATE t1
SET col3 = t2.col1
FROM table1 t1
INNER JOIN table2 t2 ON t1.col3 = t2.col1
INNER JOIN inserted i ON t1.primarykeycol = i.primarykeycol
You need to replace the .primarykeycol for the Inserted and t1 tables with the actual primary key column for your table - this is needed to link the Inserted rows with the actual data table

Related

Update table if exist or insert if not

I have 2 SQL tables with same column label, Table1 and Table2.
I want to update Table1 with value of Table2 if there is a same value for an attribute.
The tables has CODE, POSITION, DESCRIPTION as columns.
I do this:
UPDATE Table1
SET CODE = Table2.CODE,
POSITION= Table2.POSITION
FROM Table2
WHERE DESCRIPTION = Table2.DESCRIPTION
It works, but if in the DESCRIPTION Value of Table2 is not present into Table1, I want to insert the entire row, in other words I need to do something like:
UPDATE IF DESCRIPTION EXISTS
ELSE INSERT
How can I do this?
You can do this from first-principals in 2 steps
Update the existing values like you have done:
UPDATE Table1
SET
CODE= t2.CODE,
POSITION= t2.POSITION
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.DESCRITPION = t2.DESCRITPION
Then you can insert the missing records
INSERT INTO Table1 (CODE, POSITION, DESCRITPION)
SELECT CODE, POSITION, DESCRITPION
FROM Table2 t2
WHERE NOT EXISTS (SELECT DESCRITPION
FROM Table1 t1
WHERE t1.DESCRITPION = t2.DESCRITPION)
Most RDBMS have a MERGE statement that allows you to combine these two queries into a single atomic operation, you'll need to check the documentation for your vendor, but an MS SQL Server MERGE solution looks like this:
MERGE INTO Table1 AS tgt
USING Table2 AS src
ON tgt.DESCRITPION = src.DESCRITPION
WHEN MATCHED
THEN UPDATE SET CODE= src.CODE,
POSITION= src.POSITION
WHEN NOT MATCHED THEN
INSERT (CODE, POSITION, DESCRITPION)
VALUES (src.CODE, src.POSITION, src.DESCRITPION)
An additional benefit to the MERGE clause is that it simplifies capturing the changed state into the OUTPUT clause which allows for some complex logic all while keeping the query as a single operation without having to manually create and track transaction scopes.

Inserting new rows in table if already not exisitng

I have a table than over time can get bigger and I want to insert some of its rows in another table but I also want to make sure I am not duplicating the rows that I had inserted before.
So here is the type of condition for my insert:
INSERT INTO SecondTable(Col1,Col2)
SELECT Col5,Col6
FROM
FirstTable ft
WHERE ft.RecType = 'ABC'
So if I keep running this it will keep inserting the same rows again and again. How can I tell it only insert if it is not already there?
You can use not exists:
INSERT INTO SecondTable(Col1,Col2)
SELECT Col5,Col6
FROM FirstTable ft
WHERE ft.RecType = 'ABC' AND
NOT EXISTS (SELECT 1 FROM SecondTable t2 WHERE t2.col1 = ft.col5 AND t2.col2 = ft.colt6);
Generate unique constraint on table with proper columns which identifies unicity. This will also help you to preserve integrity of your table. when you try to insert records into the RDBMS will give you an error.
ALTER TABLE SecondTable
ADD UNIQUE (col1, col2, col3);
INSERT INTO SecondTable(Col1,Col2)
SELECT Col5,Col6
FROM FirstTable ft
LEFT JOIN SecondTable st ON st.Col1 = ft.Col1
WHERE st.Col1 IS NULL AND ft.RecType = 'ABC'

Aster UPDATE Column Does Not Exist

I am attempting to UPDATE the values of a column in one table based on the count of values in a source table. I am using Teradata Aster.
When I submit the following correlated subquery, I get an error stating the column does not exist despite verifying that it does exist.
UPDATE table2
SET column =
(
SELECT count(*)
FROM table1
WHERE table2.column = table1.column
)
I feel there is something idiosyncratic about Aster, but I'm not certain.
You could use below query for simple column update from another table.
UPDATE table1
SET col2 = table2.col2
FROM table2
WHERE table1.col1 = table2.col1;
and for aggregate function in update query you could use below query.
UPDATE table1
SET col2 = table2.col2
FROM (select col1, count(col2) col2 from table2 group by col1 ) table2
WHERE table1.col1 = table2.col1;
Both the queries works fine for me.

How to select a value that can come from two different tables?

First, SQL is not my strength. So I need help with the following problem. I'll simplify the table contents to describe the problem.
Let's start with three tables : table1 with columns id_1 and value, table2 with columns id_2 and value, and table3 with columns id_3 and value. As you'll notice, a field value appears in all three tables, while ids have different column names. Modifying column names is not an option because they are used by Java legacy code.
I need to set table3.value using table1.value or table2.value according to the fields table1.id_1, table2.id_2 and table3.id_3.
My last attempt, which describes what I try to do, is the following:
UPDATE table3
SET value=(IF ((SELECT COUNT(\*) FROM table1 t1 WHERE t1.id_1=id_3) > 0)
SELECT value FROM table1 t1 WHERE t1.id_1=id_3
ELSE IF ((SELECT COUNT(\*) FROM table2 t2 WHERE t2.id_2=id_3)) > 0)
SELECT value FROM table2 t2 WHERE t2.id_2=id_3)
Here are some informations about the tables and the update.
This update will be included in an XML file used by Liquibase.
It must work with Oracle or SQL Server.
An id from table3.id_3 can be found at most once in table1.id_1 or in table2.id_2, but not in both tables simultaneously.
If table3.id_3 is not found in table1.id_1 nor in table2.id_2, table3.value remains null.
As you can imagine, my last attempt failed. In that case, the IF command was not recognized during the Liquibase update. If anyone has any ideas how to deal with this, I'd appreciate. Thanks in advance.
I don't know Oracle very well, but a SQL Server approach would be the following using COALESCE() and OUTER JOINs.
Update T3
Set Value = Coalesce(T1.Value, T2.Value)
From Table3 T3
Left Join Table2 T2 On T3.Id_3 = T2.Id_2
Left Join Table1 T1 On T3.Id_3 = T1.Id_1
The COALESCE() will return the first non-NULL value from the LEFT JOIN to tables 1 and 2, and if a record was not found in either, it would be set to NULL.
It is Siyual's UPDATE written with MERGE operator.
MERGE into table_1
USING (
SELECT COALESCE(t2.value, t3.value) as value, t1.id_1 as id
FROM table_1 t1, table_2 t2, table_3 t3
WHERE t2.id_2 = t3.id_3 and t1.id_1 = t2.id_2
) t on (table_1.id_1 = t.id)
WHEN MATCHED THEN
UPDATE SET table_1.value = t.value
This should work in Oracle.
In Oracle
UPDATE table3 t
SET value=COALESCE((SELECT value FROM table1 t1 WHERE t1.id_1=t.id_3),
(SELECT value FROM table2 t2 WHERE t2.id_2=t.id_3))
Given your assumption #3, you can use union all to put together tables 1 and 2 without running the risk of duplicating information (at least for the id's of interest). So a simple merge solution like the one below should work (in all DB products that implement the merge operation).
merge into table3
using (
select id_2 as id, value from table2
union all
select id_3, value from table 3
) t
on table3.id_3 = t.id
when matched
then update set table3.value = t.value;
You may want to test the various solutions and see which is most effective for your specific tables.
(Note: merge should be more efficient than the update solution using coalesce, at least when relatively few of the id's in table3 have a match in the other tables. This is because the update solution will re-insert NULL where NULL was already stored when there is no match. The merge solution avoids this unnecessary activity.)

Copy data from table to table doing INSERT or UPDATE

I need to copy a lot of data from one table to another. If the data already exists, I need to update it, otherwise I need to insert it. The data to be copied is selecting using a WHERE condition. The data has a primary key (a string of up to 12 characters).
If I was just inserting the data, I would do
INSERT INTO T2 SELECT COL1, COL2 FROM T1 WHERE T1.ID ='I'
but I cannot figure out how to do the INSERT / UPDATE. I keep seeing references to upserts and MERGE, but MERGE appears to have issues,and I cannot figure ut how to do the upsert for multiple records.
What is the best solution for this?
If you want to avoid merges (though you should not be afraid of it) you can do something like
update t2
set col1 = t1.col1
,col2 = t1.col2
from t2
join t1
on t2.[joinkey] = t1.[joinkey]
where [where clause]
And after for the ones that you do not have
insert into t2(col1,col2)
select col1,col2 from t1
where not exists (select * from t2 where t1.[joinkey] = t2.[joinkey])
in such way you first update the ones that match and then insert the ones that do not. Also if you want it in one go you can wrap it in a transaction.
It is commonly known as UPSERT operation. Yes you are correct in saying merge has some issues with it so stay away from it.
A simple approach assuming there is a Primary Key column in Both tables called PK_Col would be something like this...
BEGIN TRANSACTION;
-- Update already existing records
UPDATE T2
SET T2.Col1 = T1.Col1
,T2.Col2 = T1.Col2
FROM T2 INNER JOIN T1 ON T2.PK_COl = T1.PK_Col
-- Insert missing records
INSERT INTO T2 (COL1, COL2 )
SELECT COL1, COL2
FROM T1
WHERE T1.ID ='I'
AND NOT EXISTS (SELECT 1
FROM T2
WHERE T2.PK_COl = T1.PK_Col )
COMMIT TRANSACTION;
Wrap the whole UPSERT operation in one transaction.
You can use IF EXISTS something like:
if exists (select * from table with (updlock,serializable) where key = #key)
begin
update table set ...
where key = #key
end
else
begin
insert table (key, ...)
values (#key, ...)
end
Another solution is to check ##ROWCOUNT
UPDATE MyTable SET FieldA=#FieldA WHERE Key=#Key
IF ##ROWCOUNT = 0
INSERT INTO MyTable (FieldA) VALUES (#FieldA)