SQL - trigger select into after update/insert - sql

i have a table called Audit_Data, and from time to time there is an update coming. Every single update consists of around 300 rows (around 20 columns per row), and all of the rows from the same update share the same Audit_ID.
I have a select, that pulls out only this data, which is relevant for me. It basically transform the 300x20 field data into one row of data.
Is there a way to create a SQL trigger, that would perform the select on the updated Audit_Data table, and insert selected data into table named Audit_Final?
This is my select statement that i use to pull out the relevant data:
SELECT main.Audit_ID
,main.Item_19
,main.Item_1
,main.Item_7
,main.Item_8
,Item_17
,main.Item_13
,macaddr.Item_2
,macaddr.Item_16
,t1.Item_1
FROM dbo.[Audit_Data] AS main
LEFT JOIN
(
SELECT Audit_ID, Item_2, Item_16
FROM dbo.[Audit_Data] AS macaddr
WHERE
(Item_2 NOT LIKE 'Hyper-V%')
AND (Item_17 = 'connected')
AND (Item_18 IN ('10000Mbps', '1000MBps') OR ITEM_9 IS NOT NULL AND ITEM_10 IS NOT NULL)
AND (Item_18 != '100Mbps')
) macaddr ON main.Audit_ID = macaddr.Audit_ID
LEFT JOIN
(
SELECT Audit_ID, Category_ID, Item_1, Record_ordinal
FROM dbo.[Audit_Data] AS t1
WHERE
Item_1 = 'Automatyczna konfiguracja sieci przewodowej' OR Item_1 = 'dot3svc' OR Item_1 = 'Wired AutoConfig'
AND Item_3 = 'Running'
AND Category_ID = '4100'
) t1 ON main.Audit_ID = t1.Audit_ID
WHERE
main.Record_Ordinal = '2'
ORDER BY main.Audit_ID

Based on authors comment this is what is required here:
CREATE TRIGGER [TR_Audit_Data] ON [Audit_Data]
AFTER UPDATE
AS
BEGIN
INSERT INTO [Audit_Final](cloumn_1, colum_2, ... all columns you have on target table)
/*
Paste your select query here
*/
END

Related

MERGE UPSERT DOES NOT WORK WHEN NOT MATCHED

ABC_TABLE holds history data based on UPDATED_TS column.
Requirement is to load data from a CSV file and conditions is as below:
Fetch the latest EMPLOYEE_NAME based on UPDATED_TS (query inside USING condition)
In ON condition check, if the EMPLOYEE_NAME in CSV file does not match the EMPLOYEE_NAME fetched in the USING query, a new row should be inserted
If a new TABLE_ID is present in the CSV file and the TABLE_ID does not exist in ABC_TABLE, a new record should be inserted
When executing below query, no rows get inserted for a new TABLE_ID,
MERGE INTO ABC_TABLE T
USING (SELECT EMPLOYEE_NAME
FROM ABC_TABLE
WHERE TABLE_ID = ?
AND UPDATED_TS =
(SELECT MAX(UPDATED_TS) FROM ABC_TABLE WHERE TABLE_ID = ?)) S
ON ((S.EMPLOYEE_NAME IS NULL AND ? IS NULL) OR ? = S.EMPLOYEE_NAME )
WHEN NOT MATCHED THEN
INSERT
/*
insert statement here
*/
Any help would be greatly appreciated.
The merge documentation says:
Use the ON clause to specify the condition upon which the MERGE operation either updates or inserts. For each row in the target table for which the search condition is true, Oracle Database updates the row with corresponding data from the source table. If the condition is not true for any rows, then the database inserts into the target table based on the corresponding source table row.
For both matched and not-matched, there has to be a row in the source table (your S subquery in this case) for anything to happen. If the passed-in values don't exist then your subquery finds no rows, so source table is empty, and thus nothing happens.
You could add an aggregate function call in your subquery so it always finds something, and use that (e.g. a count of found records) to decide if it's matched; something like:
MERGE INTO ABC_TABLE T
USING (SELECT :table_id AS TABLE_ID, :employee_name AS EMPLOYEE_NAME, count(*) AS FOUND
FROM ABC_TABLE
WHERE TABLE_ID = :table_id
AND ((EMPLOYEE_NAME IS NULL AND :employee_name IS NULL)
OR EMPLOYEE_NAME = :employee_name)
AND UPDATED_TS =
(SELECT MAX(UPDATED_TS) FROM ABC_TABLE WHERE TABLE_ID = :table_id)) S
ON (S.FOUND > 0)
WHEN NOT MATCHED THEN
INSERT (table_id, updated_ts, employee_name)
VALUES (S.TABLE_ID, systimestamp, S.EMPLOYEE_NAME)
But as you're only inserting and never updating, why not just use an insert?
INSERT INTO ABC_TABLE T (table_id, updated_ts, employee_name)
SELECT :table_id, systimestamp, :employee_name
FROM DUAL
WHERE NOT EXISTS (
SELECT null
FROM ABC_TABLE T2
WHERE T2.TABLE_ID = :table_id
AND ((T2.EMPLOYEE_NAME IS NULL AND :employee_name IS NULL)
OR T2.EMPLOYEE_NAME = :employee_name)
AND UPDATED_TS =
(SELECT MAX(UPDATED_TS) FROM ABC_TABLE WHERE TABLE_ID = :table_id)
)
I'm not sure you actually want the UPDATED_TS check in either case though.

Find entryno set from multiple set of records

I have two SQL temp tables #Temp1 and #Temp2.
I want to get entryno which contain set of temp table two.
For example: #Temp2 has 8 records. I want to search in #Temp1 which contains a set of records from #Temp1.
CREATE TABLE #Temp1 (entryNo INT, setid INT, measurid INT,measurvalueid int)
CREATE TABLE #Temp2(setid INT, measurid INT,measurvalueid int)
INSERT INTO #Temp1 (entryNo,setid,measurid,measurvalueid )
VALUES (1,400001,1,1),
(1,400001,2,110),
(1,400001,3,1001),
(1,400001,4,1100),
(2,400002,5,100),
(2,400002,6,102),
(2,400002,7,1003),
(2,400002,8,10004),
(3,400001,1,1),
(3,400001,2,110),
(3,400001,3,1001),
(3,400001,4,1200)
INSERT INTO #Temp2 (setid,measurid,measurvalueid )
VALUES (400001,1,1),
(400001,2,110),
(400001,3,1001),
(400001,4,1100),
(400002,5,100),
(400002,6,102),
(400002,7,1003),
(400002,8,10004)
I want output
EntryNo
1
2
It contains two sets.
One is:
(400001,1,1),
(400001,2,110),
(400001,3,1001),
(400001,4,1100)
The second is:
(400002,5,100),
(400002,6,102),
(400002,7,1003),
(400002,8,10004)
Try this:
WITH DataSourceInialData AS
(
SELECT *
,COUNT(*) OVER (PARTITION BY [entryNo], [setid]) AS [GroupCount]
FROM #Temp1
), DataSourceFilteringData AS
(
SELECT *
,COUNT(*) OVER (PARTITION BY [setid]) AS [GroupCount]
FROM #Temp2
)
SELECT A.[entryNo]
FROM DataSourceInialData A
INNER JOIN DataSourceFilteringData B
ON A.[setid] = B.[setid]
AND A.[measurid] = B.[measurid]
AND A.[measurvalueid] = B.[measurvalueid]
-- we are interested in groups which are passed completely by the filtering groups
AND A.[GroupCount] = B.[GroupCount]
GROUP BY A.[entryNo]
-- aftering joining the rows, the filtered rows must match the filtering rows
HAVING COUNT(A.[setid]) = MAX(B.[GroupCount]);
The algorithm is simple:
we count how many rows exists per data group
we count how many rows exists per filtering group
we join the initial data and the filtering data
after the join we count how many rows are left in the initial data and if there count is equal to the filtering count for the given group
and the result is:
Note, that I am checking for each match. For example, if in your sample data, there is one more row for entryNo = 1 it won't be included in the result. In order to change this behavior, comment this row:
-- we are interested in groups which are passed completely by the filtering groups
AND A.[GroupCount] = B.[GroupCount]

upsert into oracle

I have a table table with columns id, name, position, capture_date, modified_date, comments.
I am trying to do a simple upsert which is driving me crazy.
When the table is empty, it has to insert, but when its not empty it has to update the comments column row which has the same position, if its different it has to insert a new row instead of updating the existing one.
When the table is empty, i used this merge statement to create the first row.
This works fine.
But, second row has to be
1, john, 2, 01-JUL-15, 23-JUL-15, 'world'
In this case, the data is almost same except that the position value is 2, so a new row has to be inserted instead of updating the existing row's position to 2.
That is what my merge statement is doing. Any ideas to work on this please.
merge into customers a
using(select 1 as customer_id, 'john' as customer_name, '1' as position, '01-JUL-15' as capture_date,
sysdate as modified_date, 'hello' as comments from dual) b
on(a.customer_id=b.customer_id)
when matched then
update set a.customer_id = b.customer_id, a.customer_name = b.customer_name,
a.position = b.position, a.capture_date= b.capture_date, a.modified_date = b.modified_date,
a.comments=b.comments
when not matched then
insert(a.customer_id, a.customer_name, a.position, a.capture_date, a.modified_date, a.comments)
values(b.customer_id, b.customer_name, b.position, b.capture_date, b.modified_date, b.comments)
I have created the sqlfiddle
So lessons learned:
1 post the original query not some faulty surrogate.
2 post any error message you get.
The error message you get is:
ORA-38104: Columns referenced in the ON Clause cannot be updated: "A"."CUSTOMER_ID"
Solution: remove a.customer_id from the update clause.
merge into customers a
using (select 1 as customer_id
,'john' as customer_name
,'1' as position
,'01-JUL-15' as capture_date
,sysdate as modified_date
,'hello' as comments
from dual) b
on (a.customer_id = b.customer_id)
when matched then
update
set a.customer_name = b.customer_name
,a.position = b.position
,a.capture_date = b.capture_date
,a.modified_date = b.modified_date
,a.comments = b.comments
when not matched then
insert
(a.customer_id
,a.customer_name
,a.position
,a.capture_date
,a.modified_date
,a.comments)
values
(b.customer_id
,b.customer_name
,b.position
,b.capture_date
,b.modified_date
,b.comments)

SQL INSERT missing rows from Table A to Table B

I'm trying to insert rows into table 'Data' if they don't already exist.
For each row in Export$, I need the code to check 'Data' for rows that match both Period (date) and an ID (int) - if the rows don't already exist then they should be created.
I'm pretty sure my 'NOT EXISTS' part is wrong - what's the best way to do this? Thanks for all your help
IF NOT EXISTS (SELECT * FROM Data, Export$ WHERE Data.ID = Export$.ID AND Data.Period = Export$.Period)
INSERT INTO Data (Period, Performance, ID)
SELECT Period, [Return], [ID] FROM Export$
try something like, will need tweaking to fit your tables
insert into data
select * from export
left join data on data.id = export.id
and data.period = export.period
where data.id is null
try this:
INSERT INTO Data (Period, Performance, ID)
SELECT Period, [Return], [ID]
FROM Export$ e
where not exists (
select *
from Data
where ID = e.ID and Period = e.Period)

Can I select the data of a given row and column while executing a sql statement

To clarify the title, in a select statement, in the where clause, I need to verify to table on which I am doing using another select. In that second select, I have to find all the secondary ID. Here is what I have worked out so far
Declare #id INT
--inserting values in temp table
SELECT
rn = ROW_NUMBER() OVER (ORDER BY adt_trl_dt_tm),
*
INTO #Temp
FROM dbo.EVNT_HSTRY
ORDER BY adt_trl_dt_tm DESC
--Searching for items that are deleted and have not been restored
SELECT *
FROM dbo.EVNT_HSTRY hstry
WHERE evnt_hstry_cd LIKE '3' and
adt_trl_dt_tm > (SELECT adt_trl_dt_tm FROM dbo.EVNT_HSTRY WHERE evnt_id = evnt_id
DROP TABLE #Temp
To clarify the code, evnt_id is a foreign key. The primary key is evnt_Hstry_id. The evnt_hstry_cd 3 means deleted. What I am trying to do is to see if the field adt_trl_dt_tm (lastest date modified) of the row being read is the latest by comparing it with all the adt_trl_dt_tm fields that have the same evnt_id.
The table I am doing the select on is the table where we store the history of the events. It is where we say when the event has been added, modified, deleted and or restored.
Sadly, I cannot do that into my application as this statement is being run in an SSIS.
Overall, I need to compare the adt_trl_dt_tm with the other adt_trl_dt_tm that have the same evnt_id and select the latest.
Can you test this with your data ?
SELECT *
FROM dbo.EVNT_HSTRY hstry
WHERE evnt_hstry_cd LIKE '3' and
not exists (select 1 from EVNT_HSTRY WHERE hstry.evnt_id = evnt_id
AND Hstry.adt_trl_dt_tm > adt_trl_dt_tm)
SELECT *
FROM dbo.EVNT_HSTRY hstry
WHERE evnt_hstry_cd = '3' and
adt_trl_dt_tm = (
SELECT max(adt_trl_dt_tm) FROM dbo.EVNT_HSTRY WHERE evnt_id = hstry.evnt_id
)
will result in a row read if the code 3 is the most recent entry in hstry and no row if there is a more recent row not having code 3
Change LIKE in = if it matches exactly