Trigger failure AFTER UPDATE on MariaDB - sql

I am trying to automate some tasks within a DB rather than in the app. We have a small MariaDB for tickets to be sold. When a ticket is sold, its status needs to be set to NOT_VALID until payment is made. After payment is made, the ticket needs to be set to VALID. The invoice itself is in a table 'som_accounting' and with a reference table (som_accountingtickets - because of lazy design decisions) it points to the tickets. Now I am trying to automate that the flag in the ticket table is set to VALID when the PAYMENTSTATUS column in the accounting table changes from OPEN (1) to PAYED (3).
When I use this on the console (dbeaver or terminal) it works fine:
UPDATE som_ticket SET ID_ticketstatus = 4, activation_date = CURRENT_DATE()
WHERE ticketID IN
(SELECT act.ID_ticket FROM som_accountingticket act
INNER JOIN (SELECT * FROM som_accounting) AS ac
ON ac.accountingID = act.ID_accounting
INNER JOIN (SELECT * FROM som_ticket) AS t2
ON t2.ticketID = act.ID_ticket AND t2.ID_ticketstatus = '1'
WHERE act.ID_accounting = '565');
Now I put this into a trigger an I got an error:
CREATE DEFINER=`<user>`#`%` TRIGGER `somt_au_accounting`
AFTER UPDATE
ON `som_accounting`
FOR EACH ROW BEGIN
IF NEW.ID_paymentstatus = 3 AND OLD.ID_paymentstatus = 1 THEN
UPDATE som_ticket SET ID_ticketstatus = '4',
activation_date = CURRENT_DATE()
WHERE ticketID IN
(SELECT act.ID_ticket FROM som_accountingticket act
INNER JOIN (SELECT * FROM som_accounting) AS ac
ON ac.accountingID = act.ID_accounting
INNER JOIN (SELECT * FROM som_ticket) AS t2
ON t2.ticketID = act.ID_ticket
AND t2.ID_ticketstatus = '1'
WHERE act.ID_accounting = OLD.accountingID);
END IF;
END
Database reports this:
Error synchronizing data with database
Reason:
SQL-Fehler [08]: (conn:3) Could not read resultset: unexpected end of stream, read 0 bytes from 4
Query is: UPDATE d0294220.som_accounting
SET ID_paymentstatus=?
WHERE accountingID=?, parameters [3,568]
Why did it run well in the console but not in the trigger?
MariaDB 10.5.8

Related

Getting SQL Server Merge Error

I am trying to update the product history's average rating number by using the merge function
MERGE ProductRankingHistory P
USING Review R ON P.PRHProduct = R.ProductID
WHEN MATCHED THEN
UPDATE
SET P.PRHAverageRating = (SELECT AVG(ReviewRateValue)
FROM Review
WHERE ProductID = P.PRHProduct
AND YEAR(ReviewRateDate) = PRHYear);
And I get this error:
Msg 8672, Level 16, State 1, Line 2
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Merge seems unnecessary for this logic. Something like:
UPDATE ProductRankingHistory P
SET PRHAverageRating = (SELECT AVG(r.ReviewRateValue)
FROM Review r
WHERE r.ProductID = P.PRHProduct AND YEAR(r.ReviewRateDate) = P.PRHYear
)
WHERE EXISTS (SELECT 1
FROM Review r
WHERE r.ProductID = P.PRHProduct AND YEAR(r.ReviewRateDate) = P.PRHYear
);
After writing this, I see that you are probably using SQL Server (or a similar database). The following might work:
UPDATE p
SET PRHAverageRating = rp.avg_ReviewRateValue
FROM ProductRankingHistory p JOIN
(SELECT r.ProductID, YEAR(r.ReviewRateDate) as yyyy, AVG(r.ReviewRateValue) as avg_ReviewRateValue
FROM Review r
GROUP BY r.ProductID, YEAR(r.ReviewRateDate)
) rp
ON rp.ProductId = p.PRHProduct AND rp.yyyy = p.prhYear;

How to avoid SQL query timeout error when open transaction is there?

I have used below query to retrieve customer details from database.
Method 1:
BEGIN TRAN
IF EXISTS(SELECT TOP 1 'X' From CUSTOMER Where CustId = #Code AND Status = 'D')
BEGIN
UPDATE CUSTOMER
SET Status = 'L'
WHERE CustId = #BorrowerCode AND ISNULL(Borrower,'') = 'Y'
SELECT CustId, MobileNo, PlaceDesc
FROM CUSTOMER C
JOIN PLACE P ON C.FKID = P.Pk_Id
WHERE Cust_Id = #Code AND C.Status = 'L'
END
COMMIT TRAN
Method 2:
BEGIN TRAN
IF EXISTS(SELECT TOP 1 'X' From CUSTOMER Where CustId = #Code AND Status = 'D')
BEGIN
UPDATE CUSTOMER
SET Status = 'L'
WHERE CustId = #BorrowerCode AND ISNULL(Borrower,'') = 'Y'
SELECT CustId, MobileNo, PlaceDesc
FROM CUSTOMER C With(NoLock)
JOIN PLACE P With(NoLock) ON C.FKID = P.Pk_Id
WHERE Cust_Id = #Code AND C.Status = 'L'
END
COMMIT TRAN
If there is an open transaction in database, the query will fail with a timeout for method 1. Is it good practice to use NoLock inside transaction?
Few things..
1.First of all your update is not sargable,you can try to rewrite it as below
UPDATE CUSTOMER
SET Status = 'L'
WHERE CustId = #BorrowerCode AND Borrower = 'Y'
2.Time out has pretty huge limit,25 times query cost.so even with this limit,if you are getting time out ,then there must be some thing wrong and we are trying to apply bandage with nolock.setting isolation level to snapshot ,will not result in blockings of select ,but it comes with a cost of tempDB usage,scan issues(see link below for more..).Further isolation level wont apply to DDL/DML statements ,they are just for select statements and in your case ,an open transaction may mean some DDL/DML running for so long.
In summary,i wont use nolock,but i would rather try to see why timeout happens and also changing isolation level requires some testing as well
References:
http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/

Oracle vs MS SQL UPDATE using IN SELECT

This SQL works fine on MS SQL Server but produces an error "ORA-00907: missing right parenthesis".
SQL:
UPDATE DELIVERY
SET VISIBLE = 0
WHERE DELIVERY.ID
IN
(
SELECT DELIVERY.ID FROM delivery WHERE DELIVERY.VISIBLE = 1
EXCEPT
SELECT DELIVERY.ID FROM delivery LEFT JOIN inventory ON INVENTORY.DELIVERYID = DELIVERY.ID
WHERE ((DELIVERY.VISIBLE = 1) AND (INVENTORY.VISIBLE = 1)) AND (INVENTORY.INVENTORYSTATE = 3)
);
Is there a way to get this to work on Oracle or is an UPDATE using an IN with SELECT statements just conceptually wrong?
In Oracle, IN Can also work, just change the EXCEPT to MINUS in Oracle
http://www.techonthenet.com/sql/update.php
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10007.htm
http://docs.oracle.com/cd/E17952_01/refman-5.0-en/exists-and-not-exists-subqueries.html
An Sample Example for this will be
UPDATE DELIVERY
SET VISIBLE = 0
WHERE DELIVERY.ID
IN
(
(SELECT DELIVERY.ID FROM delivery WHERE DELIVERY.VISIBLE = 1)
MINUS
(SELECT DELIVERY.ID
FROM delivery LEFT JOIN inventory ON INVENTORY.DELIVERYID = DELIVERY.ID
WHERE (((DELIVERY.VISIBLE = 1) AND (INVENTORY.VISIBLE = 1))
AND (INVENTORY.INVENTORYSTATE = 3)))
);
I think you can modify this query so that it works in both SQL Server and Oracle:
UPDATE delivery d
SET d.visible = 0
WHERE d.visible = 1
AND NOT EXISTS ( SELECT 1 FROM inventory i
WHERE i.deliveryid = d.id
AND i.visible = 1
AND i.inventorystate = 3 )
This will update DELIVERY setting visible = 0 wherever visible = 1 but there is no corresponding record in INVENTORY with visible = 1 and inventorystate = 3.

Using query results in further procedcures

I'm fairly new to SQL especially PL/SQL, I have a grasp of the basics but what i'm trying to do goes over my head. This is a small part of a larger system but I will focus on 3 tables Sale_Head, Sale_Line and Product. This work is being done in Orcale SQL developer.
http://imgur.com/OrfhM0g,i4pMnTx - Sale Table
http://imgur.com/OrfhM0g,i4pMnTx#1 - Product Table
(Im a newbie so i dont have enough rep to directly post images)
Im attempting to build up some procedures that process pending sales. Sales have a status in the Sale_Head which can either be p(pending), s(shipped), i(in progress), x(cancelled), or b(back orders). The procedure(s) need to find sales with a pending status (i've got that far in my code), then check the products stock levels are above the minimum level enough to complete the sale. If all these conditions are met pending sales become i (in progress) and if there is inadequate stock it comes backordered (b). I have a general idea of how to go about this, but when it comes having to referencing the product table using the foreign from sale_line I get confused.
--create or replace procedure Process_Products is
--begin
select Sale_Head.Sale_Num , Sale_Line.Product_Code as
from Sale_Head
inner join Sale_Line on
Sale_Head.Sale_Num = Sale_Line.SALE_NUM
where Sale_head.Status = 'P';
--if Sale_Line.Product_Code = Product.Product_Code >
--end;
This returns the product codes for orders that have a pending status, but now I need to check their stock levels in the product table and make adjustments.
Please correct me if I am wrong, but if you are saying "for those sales in a pending status where enough inventory exists to fulfill the order, change the status to i (in progress), otherwise not enough inventory exists, so change the status to b (backordered)", then the following should help:
-- This is a useful query to display what you need - debugging, use in cursor, etc
SELECT sh.Sale_Num, sl.Product_Code, sl.Quantity as QtyToBuy,
p.Stock_Count, p.Minimum_Level,
(Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE Sale_head.Status = 'P';
The status code can be updated in one query if that is what you want:
--This query will actully do the update (if view is updatable)
UPDATE
(
SELECT sh.Status, (Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE sh.Status = 'P'
) a
SET a.Status = a.NewStatus;
If the above view is not updatable, try this syntax:
--Otherwise try this syntax
UPDATE Sale_Head sh1 Set Sale_Head.Status =
SELECT (Case When sl.Quantity <= p.Minimum_Level Then 'i'
Else 'b' end) as NewStatus
FROM Sale_Head sh
INNER JOIN Sale_Line sl
ON sh.Sale_Num = sl.SALE_NUM
INNER JOIN Product p
ON sl.Product_Code
WHERE sh1.Sale_Num = sh.Sale_Num
)
WHERE Sale_Head.Status = 'P';

SQL Server:An expression of non-boolean type specified in a context where a condition is expected

I apologize I'm asking this question when this specific error type has already been asked multiple times before, but I've looked through them and am not explicitly seeing my answer.
I am trying to build a trigger that takes records inserted into a table (FDC_Trip_History), selects some information from the record, joins on other tables to pull additional data, etc. and inserts a record into another table (Staging).
I'm getting this error at the bottom of my script, the 4th line from the end after the FROM section. Any idea why?
CREATE TRIGGER Insert_Trip_History ON FDC_Trip_History
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
--If inserted record reaches a certain 'status' of archive then continue
If EXISTS (SELECT * FROM inserted WHERE inserted.description like '%archive%')
BEGIN
--If inserted record can be 'billed', and hasn't already been processed, then continue.
IF EXISTS ( SELECT * FROM inserted
INNER JOIN FDC_Trips on inserted.tdate = FDC_Trips.tdate and inserted.job = FDC_Trips.job and inserted.SourceDB = FDC_trips.sourceDB
INNER JOIN AMS.dbo.Billable_Outcome_Filter as eBill on FDC_trips.SourceDB = eBill.SourceDB and FDC_Trips.outcome = eBill.Outcome_Code)
AND NOT EXISTS ( SELECT * FROM inserted
INNER JOIN Staging as Stg on inserted.tdate = Stg.tdate and inserted.job = Stg.job and inserted.sourcedb = Stg.sourceDB)
BEGIN
INSERT INTO Staging
(EVENT_OPERATION,
EVENT_SOURCE_TABLE,
EVENT_PRIORITY,
EVENT_TIME_UPDATED,
EVENT_STATUS,
EVENT_COMMENT,
TDATE,
JOB,
SOURCEDB,
CUSTNO,
SHIFTNO,
TYPE,
PROFITCENTER,
BILLINGRATEPROFITCENTER)
SELECT
'CREATE' as [EVENT_OPERATION],
'FDC_Trip_History' as [EVENT_SOURCE_TABLE],
'1' as [EVENT_PRIORITY],
GETDATE() as [EVENT_TIME_ADDED],
null as [EVENT_TIME_UPDATED],
'0' as [EVENT_STATUS],
'' as [EVENT_COMMENT],
eTHistory.tdate as [TDATE],
eTHistory.job as [JOB],
eTHistory.sourcedb as [SOURCEDB],
eT.custno as [CUSTNO],
eT.shiftno as [SHIFTNO],
'Completed' as [TYPE],
--Decide Profit Center. Profit center (PC) determined from dispatch zone (Trips.dzone)
CASE
WHEN cType.descr LIKE 'ATS%'
THEN DispatchZone.ATS_ProfitCenter
ELSE DispatchZone.ProfitCenter
END,
--Decide Billing rate profit center. Billing rate profit center (BRPC) determined from pickup zone. Does ATS logic apply to BRPC too?
CASE
WHEN cType.descr LIKE 'ATS%'
THEN PickupZone.ATS_ProfitCenter
ELSE PickupZone.ProfitCenter
END
as [BILLINGRATEPROFITCENTER]
FROM inserted
INNER JOIN FDC_Trip_History as eTHistory
INNER JOIN FDC_Trips as eT on eTHistory.tdate = eT.tdate and eTHistory.job = eT.job and eTHistory.sourcedb = eT.sourcedb
LEFT JOIN Trips as T on T.tdate = eTHistory.tdate and T.sourcedb = eTHistory.sourceDB and T.Job = eTHistory.Job
LEFT JOIN Call_Types as cType on cType.code = eT.calltype and cType.sourceDB = eT.sourceDB
LEFT JOIN Zones as DispatchZone on DispatchZone.code = T.dzone
LEFT JOIN Zones as PickupZone on PickupZone.code = eT.puzone /* Error pops up right here */
END
END
END
You seem to have forgotton the specify the join criteria for the FDC_Trip_History table (the first INNER JOIN).
In addition, you have 14 columns in your INSERT list but 15 in your SELECT statement.