After insert trigger failing to join two tables with values inserted by a database transaction - tsql

I have 2 table invoice_header table and invoice_line table with details below:
invoice_header colums : invoice_id, customer_id
invoice_line colums : invoice_id, line_id ,item_id, quantity, line_flag
They are joined by the common column invoice_id
Values in these 2 tables are inserted using a database transaction by the application
Tables are on Microsoft SQL Server
I created a trigger on invoice_line to update line_flag to zero if customer_id is 10. However the trigger is not working, I believe because it's failing to find a matching line in invoice_header since these two tables are inserted by a database transaction at the same time.
Below is the trigger
update invoice_line
set line_flag = 0
from invoice_line l
inner join Inserted v on v.line_id = l.line_id
inner join invoice_header h on h.invoice_id = v.invoice_id
where h.customer_id = 10
If I don't join the tables, It works but updates all the lines.
I have also tried to rewrite the trigger on the invoice_header to update the lines but it's still not working.
Is the a way to write an after insert trigger that joins tables inserted by database transaction?

I believe because it's failing to find a matching line in
invoice_header since these two tables are inserted by a database
transaction at the same time.
This is not true; the data may still not be committed for "outsiders", but your own transaction can see the data it iself has already modified.
the trigger is not working
While your question has some details, you don't mention why the trigger doesn't work. Do you mean it does nothing? Or is there an error? If so, which one?
update invoice_line
I think here's the cause for the error. You want to update l instead, since you have already aliased your table.

Related

Redshift insert a date value into a table

insert into table1 (ID,date)
select
ID,sysdate
from table2
assume i insert a record into table2 with value ID:1,date:2023-1-1
the expected result is update the ID of table1 base on the ID from table2 and update the value of date of table1 base on the sysdate from table2.
select *
from table1;
the expected result after running the insert statement will be
ID
date
1
2023-1-6
but what i get is:
ID
date
1
2023-1-1
I see a few possibilities based on the information given:
You say "the expected result is update the ID of table1 base on the ID from table2" and this begs the question - did ID = 1 exist in table1 BEFORE you ran the INSERT statement? If so are you expecting that the INSERT will update the value for ID #1? Redshift doesn't enforce or check uniqueness of primary keys and you would get 2 rows in the table1 in this case. Is this what is happening?
SYSDATE on Redshift provides the start timestamp of the current transaction, NOT the current statement. Have you had the current transaction open since the 1st?
You didn't COMMIT the results (or the statement failed) and are checking from a different session. It could also be that the transaction started before in the second session before the COMMIT completed. Working with MVCC across multiple sessions can trip anyone up.
There are likely other possible explanations. If you could provide DDL, sample data, and a simple test case so that others can recreate what you are seeing it would greatly narrow down the possibilities.

How to insert new rows only on tables without Primary or Foreign Keys?

Scenario: I have two tables. Table A and Table B, both have the same exact columns. My task is to create a master table. I need to ensure no duplicates are in the master table unless it is a new record.
problem: Whoever built the tables did not assign a Primary Key to the table.
Attempts: I attempted running an INSERT INTO WHERE NOT EXISTS query (below as an example not the actual query I ran)
Question: the portion of the query below WHERE t2.id = t1.id confuses me, my table has a multitude of columns, there is no id column like I said it has no PRIMARY key to anchor the match, so, in a scenario where all I have are values without primary keys, how can I append only new records? Also, perhaps I am going about this the wrong way but are there any other functions or options through TSQL worth considering? Maybe not an INSERT INTO statement or perhaps something else? My SQL skills aren't yet that advance so I am not asking for a solution but perhaps ideas or other methods worth considering? Any ideas are welcome.
INSERT INTO TABLE_2
(id, name)
SELECT t1.id,
t1.name
FROM TABLE_1 t1
WHERE NOT EXISTS(SELECT id
FROM TABLE_2 t2
WHERE t2.id = t1.id)
If I understand your question correctly, you would need to amend the SQL sample you posted by changing the condition t2.id = t1.id to whatever columns you do have.
Say your 2 tables have name and brand columns and you don't want duplicates, just change the sample to:
WHERE t2.name = t1.name
AND t2.brand = t1.brand
This will ensure you don't insert and rows in table 2 from table 1 which are duplicates. You would have to make sure the where condition contains all columns (you said the table schemas are identical).
Also, the above code sample copies everything into table 2 - but you said you want a master table - so you'd have to change it to insert into the master table, not table 2.

Update clause in Audit Trail Trigger

I got this trigger as a tip and I would like to know how it works with updates. It is supposed to create a record everytime there is an update or insert action on my main table.
create trigger tblTriggerAuditRecord on tblOrders
after **update, insert**
as
begin
insert into tblOrdersAudit
(OrderID, OrderApprovalDateTime, OrderStatus, UpdatedBy, UpdatedOn )
select i.OrderID, i.OrderApprovalDateTime, i.OrderStatus, SUSER_SNAME(), getdate()
from tblOrders t
inner join **inserted** i on t.OrderID=i.OrderID
end
go
From my understanding, it inserts all the inserted records to the main table to the stated columns in the audit including timestamp and user but how about the update? What if I update the rows in my main table? should not I have a joing also on the updated records?
Hope my question is clear, thanks a lot for help!
There is no table updated when a trigger is fired. In case of an update, the old values from your main table you'll find in a table deleted and the new ones are (like in case of an insert) in the table inserted.
That's the same as in this example:
UPDATE tabEmployee SET Salary = Salary * 1.05
OUTPUT inserted.EmployeeName, deleted.Salary, inserted.Salary
INTO tabSalaryHistory (EmployeeName, OldSalary, NewSalary)
In this example, every employee gets a salary increase. The value before the increase is stored in the output table deleted and the new value in inserted.
Have a look at this for better understanding.

SQL query between two tables looking for specific data in second table

I've been asked to get some data from SQL 2008R2 DB. I have two tables:
Employee table - has lots of data to include a column with either active or inactive marked for employees
Punches table - holds time clock punches with dates, times, etc & a column that says if the punch has been deleted by payroll.
I'm being asked to write a query that will give a list of active employees from table A that have no punches in table B and/or they have only punches that have been marked as deleted.
A left outer join with a null would work great if the deleted punches were actually deleted from the db instead of being marked with a deletion.
Any help would be appreciated
Thx!
~j
SELECT *
FROM EMPLOYEE E
JOIN PUNCHES P
ON E.EMPID = P.EMPID
WHERE E.ACTIVE = 'Y'
AND (P.PUNCH_TIME IS NULL OR P.DELETED = 'Y')

Merge SQL to Exclude Duplicate Records So Merge 2nd time Doesn't Fail

I have three tables and only one that I directly control and am doing a MERGE between them. See my abbreviated but working example here (sqlfiddle example).
I am doing a MERGE between table 1 and Table 2 to Table 3. Table 1 has duplicate data which the MERGE (erroneously) can handle on the first run (insert) but fails with this message on the second run (update).
The MERGE statement attempted to UPDATE or DELETE the same row more
than once.
My question is, can the MERGE be written to either use an EXCEPT such as
SELECT AdFull FROM [dbo].[Users] WHERE AdFull IS NOT NULL
EXCEPT
SELECT AdFull FROM [dbo].[Users]
WHERE AdFull IS NOT NULL
GROUP BY AdFull
HAVING COUNT(*) = 1
or a different Join to only show users that are not duplicated? Or even a way to select a specific one of the duplicates?
Answered Questions
MERGE is a working Insert due to the nature of Fiddle. But due (AFAIK) to the stateless nature of fiddle one never sees the error in Fiddle on a second run, because a merge never happens with the data, only inserts.
Ignore Rows: Actually I would eventually like to use an individual duplicate row via divining of one based on a condition. The actual data table I am dealing with away from the fiddle example has more columns and it would be nice to maybe select a specific row in a duplicate set due to a specific condition.
The example doesn't bare it out, but yes the duplicates are due to the computed AdFull column. Think of a system adding a temp employee, that user gets a row. Then the temp employee gets hired on as fulltime, keeps the ad account but then gets another row in the user table. Yes I know it shouldn't happen. So that is how a duplicate comes about.
(Duplicate values Table 3) Table three is a result table that can be cleaned out for any duplicates to start this process afresh.
In your MERGE statement can you do something similar this?
MERGE INTO [dbo].Table3 AS T3
USING
(
SELECT
AdFull,
MAX(StartedOn)
FROM [dbo].Table2 AS [ad]
GROUP BY AdFull
) AS T2
ON (T2.AdFull = T3.AdFull)
WHEN MATCHED THEN UPDATE blah
WHEN NOT MATCHED THEN INSERT blah
Using the MAX aggregate with a GROUP BY should give you only the information from when the temp was hired on. Then if the AdFull matches you can simply UPDATE Table3 with the most recent information and if there is no match then INSERT a new row.
UPDATE: If I fail to mention that MERGE should be used with caution I will take flak from #AaronBertrand.