How to solve "Warning: triggers are created with compilation errors"? - oracle

Hi sorry for the inconvenience of posting a bad question. So below is the edit version of the question:
Purpose of this task:
In this task, I am trying to apply the company’s top client is the one who has purchased the most a discount with 15% discount. One of the requirement before creating this trigger is that - should not hardcode the top client since the top client could change when more purchases are made by other clients. I have created a trigger called TOP_CLIENT and edited the code as below:
AFTER UPDATE ON PURCHASE
BEGIN
SELECT PURCHASENO FROM PURCHASE
WHERE (SELECT MAX(AMOUNT) FROM PURCHASE P
JOIN CLIENT C ON P.PURCHASENO = C.CLIENTNO);
UPDATE PURCHASE
SET AMOUNT = (AMOUNT * 0.85)
END;
/
NOTE THAT:
The table CLIENT and PURCHASE are already created and existed in the database.
Shown errors within this code:
enter image description here
Please comment if any of the above doesn't make sense or have any questions related! Thank you!

First, I suggest adding a numeric DiscountRate column to the Client discount and populating it the applicable rate for any clients who get a discount.
Next, I suggest adding a numeric column called the same DiscountRate to the Purchase table.
With those in place, you can update any purchase row AFTER INSERT OR UPDATE only if the DiscountRate has not yet been applied to the purchase or is not equal to the current client discountrate, depending on your business logic;
DROP TRIGGER TOP_DOSCOUNT;
/
CREATE TRIGGER TOP_DOSCOUNT
AFTER INSERT OR UPDATE ON PURCHASE
FOR EACH ROW
WHEN DiscountRate IS NULL
DECLARE dr PURCHASE.DiscountRate%type;
SELECT nvl(C.DiscountRate,0.0) INTO dr FROM CLIENT C
WHERE PurchaseNo = C.ClientNo;
UPDATE PURCHASE
SET Amount = Amount * (1 - dr), DiscountRate = dr;
END;
/
I am unsure if you want to constantly be updating all your prior purchase records with new discount rates. If not, then I suggest this should Only be an insert trigger...but only you know your business logic to be implemented!

Related

Change the Date of a Review in Magento

Magento reviews follow this format:-
Summary
Body of Review
Date of Review
I need to change the date of the review to a custom date.
Please could somebody guide me on how to go about doing this? I have tried editing the review in the back-end, but the only sections I can change are the Summary and the Body of the review.
If you could let me know where in the database I should change, I'd really appreciate it. Or, if there is a way to change this in the back-end, without installing an extension, that'd be really awesome.
Preface
The Magento Admin backend does not have a place to edit the date of a product review. You must do this directly in the SQL database or programmatically.
The following instructions will help you change it directly in the SQL database.
1.) Find The Review ID
Login to your Magento backend Admin area and go here in the menu:
Magento Admin >> Catalog >> Reviews and Ratings >> Customer Reviews >> All Reviews
In the resulting table of all reviews, find the single review you want to change the date for. Do not click into the review because the ID is only shown in the table of all reviews.
Remember that ID
2.) Change the Date in the Database
I used PhpMyAdmin to get access to my Magento SQL database. You can use whatever SQL Management Platform suits you.
Login to your SQL database and navigate the the table named only 'review'.
In that table you will see a column called 'review_id'.
Find the row in the 'review.review_id' column that matches the ID of the review you want to change the Magento date for.
Click 'Edit' on that row and change the 'created_at' value of it.
Save your changes to the row by clicking 'Go'.
You're done.
Check Magento to make sure it displays the updated date.
Helpful Hints
The date value in 'created_at' must be in the format of an SQL date-time. This is 'YYYY-MM-DD hh:mm:ss'.
Magento is sensitive to timezones. You may need to adjust the date value you use to compensate for this - so it displays the way you want it.
The SQL 'review' table was not listed on my first page of table names in PhpMyAdmin. To find it, I had to click through to the second page of table names.
It is very easy to ruin your website by clicking the wrong things in PhpMyAdmin. So don't screw around in there.
I'd think by directly manipulating the reviews details from Databaes. Although this seems to be discouraged but since it may be one or two records, then creating a custom solution is not feasible.
Running this MySQL to fetch the reviews info from the DB may help you locate the review you are trying to edit.
SELECT
rd.`detail_id`,
rd.`review_id`,
r.`created_at`,
rd.`title`,
rd.`detail`,
rd.`nickname`,
r.`review_id`
FROM
`review_detail` rd
LEFT JOIN review r
ON rd.`review_id` = r.`review_id`
ORDER BY rd.`detail_id` DESC
You can set all Magento 1.x reviews to the order created date us this:
START TRANSACTION;
UPDATE review r INNER JOIN review_detail rd ON (rd.review_id = r.review_id AND r.entity_id = 1) INNER JOIN sales_flat_order_item oi ON (oi.product_id = r.entity_pk_value) INNER JOIN sales_flat_order as o ON (o.entity_id = oi.order_id) SET r.created_at = o.created_at;
SELECT r.review_id, r.created_at as review_date, o.created_at as order_date, o.increment_id, oi.sku FROM review r INNER JOIN review_detail rd ON (rd.review_id = r.review_id AND r.entity_id = 1) INNER JOIN sales_flat_order_item oi ON (oi.product_id = r.entity_pk_value) INNER JOIN sales_flat_order as o ON (o.entity_id = oi.order_id) GROUP BY oi.product_id ORDER BY r.created_at DESC;
COMMIT;
Tested and verified on Magento 1.9.x

Trying to create a trigger that updates a table when a value in another table is changed (oracle apex)

So I have two tables, one is called "device" the other is "devicerequest"
The "device" table has columns including id (primary key), name, quantity and basically has data like "(1, iPhone, 3), (2, iPad, 1), which is saying: id=1 name=iPhone quantity=3.
The "devicerequest" table has columns including requestid(primary key), deviceid, devicequantity, and has data like (22, 1, 2) which means that it is requesting 2 of the iPhones.
So basically I am trying to create a trigger when the admin confirms the request (their is an approval column in "devicerequest" (which is NULL when a projectrequest is made) and sets it to 'Y' which means yes to the request, it should change the quantity column in device by subtracting the number that was requested (their is a constraint in place to make sure you do not request devicequantity > quantity).
So I have tried a ton of different variants of this, but still keep getting errors, this is what I currently have:
create or replace trigger "DEVICEREQUEST_T1"
before update on "DEVICEREQUEST"
for each row
begin
if(:NEW.approval = 'Y')
then
update device set device.quantity = device.quantity - devicerequest.devicequantity
where device.id = devicerequest.deviceid;
end if;
end;
I get these errors for this:
6 23 PL/SQL: ORA-00904: "DEVICEREQUEST"."DEVICEID": invalid identifier
5 5 PL/SQL: SQL Statement ignored
I have also tried this:
create or replace trigger "DEVICEREQUEST_QUANTITY"
BEFORE
update of "APPROVAL" on "DEVICEREQUEST"
for each row
when (NEW.approval = 'Y')
begin
update device set quantity = quantity - devicequantity where id = deviceid;
end;​
I get these errors for this:
2 67 PL/SQL: ORA-00904: "DEVICEID": invalid identifier
2 1 PL/SQL: SQL Statement ignored
I am using Oracle Application Express 4.2.5, thanks for any sort of help I have been working on this for a while and cannot figure out what is wrong.
Your UPDATE statement would be something like
update device
set device.quantity = device.quantity - :new.devicequantity
where device.id = :new.deviceid;
Of course, in a real system, if admins can be approving requests in parallel, you can easily come up with cases where this would cause the quantity to drop below 0.
You say that you have a constraint that prevents the devicequantity from exceeding the quantity but you can't have a constraint that compares data across tables. You could have a trigger that performs that validation. If so, it is highly likely that your trigger is not sufficient in a multiuser environment to enforce the constraint you expect it to be enforcing.
You could issue an update removing the requested amount at the time of the request rather than approval. If the update would cause the qty to drop below zero, you get an error, otherwise you have "reserved" that number for sale and you don't have to worry about requests coming in very close afterwards. When the request is approved, you have that amount locked in, if disapproved, update the qty to "return" the reserved amount.
You might want to adjust the process depending on the length of time between request and approval and/or if there is some way to determine the probability of approval/disapproval. You could reserve, say, 50% of the requested amount rather than all of it for lower probability requests.

PL/SQL triggers - calculate percentage

I'm struggling with a problem as I'm VERY new to PL/SQL.
I would like to create a trigger to convert a user supplied percentage value, e.g. 10%.
The column is called deposit in my Booking table. This booking table also has a total cost. I would like to calculate the deposit amount using the supplied percentage and total cost.
So, when a user types in 10% (and all the other data) it will do a calculation using total cost and when the record is inserted, instead of showing 10% it shows the deposit amount.
Although I am not sure how exactly your table looks like this may be what you are looking for:
CREATE OR REPLACE TRIGGER deposit_perc_calc BEFORE
INSERT ON booking FOR EACH ROW
BEGIN
:new.percentage := :new.total_cost*:new.percantage/100;
END;
Maybe you should check the Oracle reference for a guide on coding triggers: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#LNPLS020

Firebird performance: Update/Select verus Insert/Select last

I have to keep an account balance up to date, a log of changes, and to use it.
It seems to me that the options are to either:
keep it in a single row,
use a trigger to save changes to a separate table
use an select|update to do the update
use a simple select from the table to access the value
The alternative is:
Keep the value in a separate table,
Use Select Last and Insert to effect the update
Use Select Last from the separate table to access the value
Does anyone know which is faster? Is there much in it?
Steve
What you are proposing seems far too complicated...
I would sugest to do a different thing:
I would have two tables with a master-detail relation.
In the detail I would insert rows and its triggers would update the master table
balance (account, amount, ...)
balance_detail (account, amount, ...)
balance_detail_after_insert
begin
update master
set amount = amount + new.amount
where account = new.account;
end
balance_detail_after_update
begin
update master
set amount = amount + new.amount - old.amount
where account = new.account;
end
balance_detail_after_delete
begin
update master
set amount = amount - new.amount
where account = new.account;
end
After any change you should simply close/open the master table to refresh data.

Oracle Trigger to remove stock quantity from products and add to orderline

I apologise in advance for this confusing question, wall of text, and awful trigger. I'm designing a small database for a retail store that takes orders in-store and then delivers the products from the onsite warehouse/stockroom.
Now the order entity has a one-to-many relationship to an order_line entity which in turn has a many to one relationship with product (which itself is stored in the stock etc). The order_line entity is the link entity and solves the many-to-many relationship so that's all good. Just to clarify, it's one order_line per product.
What I want to do is when an order_line (which has a quantity attribute) is created, I want the trigger to first check the appropriate product has sufficient stock (so if quantity is 3, stock must be at least 3), otherwise it must throw an error.
If successful I want it to update the quantity and stock attributes accordingly. I'd also like it to add a subtotal value to the order_line (I've yet to attempt this) which in turn can then be used to calculate the total value in the order entity.
So at this stage I'm looking for a bit of guidance because I'm quite confused with this, now.
CREATE OR REPLACE TRIGGER check_order_line
BEFORE INSERT OR UPDATE ON order_line
for each row
BEGIN
select order_line.quantity, products.stock from order_lines right join products on order_line.product_no=products.product_no;
if(order_line.quantity>products.stock) then
RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock');
ELSE
products.stock := products.stock - quantity;
dbms_output.put('Successful');
END IF;
END;
.
run
Errors I am getting:
2/1 PL/SQL: SQL Statement ignored
2/49 PL/SQL: ORA-00942: table or view does not exist
3/1 PL/SQL: Statement ignored
3/15 PLS-00357: Table,View Or Sequence reference 'ORDER_LINE.QUANTITY'
not allowed in this context
What I've tried:
I'm not sure about the first two errors; the table in question is
definitely called order_line, perhaps I've missed something obvious.
I've also tried declaring variables for products.stock and order_line
quantity to solve the last error - this compiles IIRC but doesn't
actually work as I guess it's not updating the table.
I'm not worried so much about the else action, I probably need an update
table statement there but for now I'm just focusing on getting the
trigger condition to work.
If any one could point me in the right
direction and point out any hilarious errors I'd appreciate it.
Thank you very much for your time, I apologise for scarring your eyes with this monstrosity of a trigger.
Put a constraint on products.stock to enforce the value is > -1:
ALTER TABLE products add CONSTRAINT has_stock CHECK (stock >-1);
Then do the update and insert as a single transaction.
UPDATE product SET products.stock = products.stock - quantity_required
WHERE product_id=id_of_product
INSERT INTO order_line ...............
COMMIT;
The transaction will always fail if there is not enough stock, and you will not have the problems associated with triggers.
Assuming you do not have the stock price at this point you could get it by using the RETURNING clause on your update (you will need to DECLARE the variable v_product_cost to hold the value) e.g:
UPDATE product SET products.stock = products.stock - quantity_required
WHERE product_id=id_of_product
RETURNING products.value INTO v_product_cost
You can then use this value in the insert that follows.
The run command at the end doesn't make sense. That's SQL Server syntax.
In your query, you're referencing a table ORDER_LINES (plural). But the trigger is defined on a table ORDER_LINE (singular). I assume that you don't have both an ORDER_LINE and an ORDER_LINES table so I expect that you intended your query to reference the ORDER_LINE table.
A row-level trigger defined on table A cannot in general query table A. So since your trigger is defined on ORDER_LINE, it cannot query ORDER_LINE. It appears that you really just want the information about the row that caused the trigger to fire so you don't actually need to join to the ORDER_LINE table. You just need to reference attributes from the :NEW record.
A SELECT statement in PL/SQL needs to do something with the results. Presumably, your intention is to do a SELECT ... INTO a local variable.
If you want to update the PRODUCTS table, you'd need to do an actual UPDATE.
Putting all that together, my guess is that you're trying to create a trigger that looks something like
CREATE OR REPLACE TRIGGER check_order_line
BEFORE INSERT OR UPDATE ON order_line
for each row
DECLARE
l_current_stock products.stock%type;
BEGIN
select products.stock
into l_current_stock
from products
where product_no = :new.product_no;
if(:new.quantity > l_current_stock) then
RAISE_APPLICATION_ERROR(-20103, 'Insufficient Stock');
else
update products
set stock := stock - :new.quantity
where product_no := :new.product_no;
end if;
END;
All that being said, however, a trigger would not generally be the correct way to solve this sort of problem. From a maintenance standpoint if nothing else, having a stored procedure PROCESS_ORDER that inserts all the ORDER_LINE rows and updates all the PRODUCTS rows will be much easier to follow and debug. The more business logic that is embedded in triggers the harder it is to follow the flow of the application and the easier it is to end up with a rat's nest of unintentional updates that are nearly impossible to unwind.
Also, be aware of what happens in a multi-user system. Session A can query the PRODUCTS table and see a STOCK of 5 and accept an order for 4 units of that product. But before session A issues a commit, session B also queries the same row of the PRODUCTS table, sees the same STOCK of 5, and accepts an order for 3 units. Session B's UPDATE statement will block until session A commits. But then if A commits and B commits, both orders will have been entered and the PRODUCTS table will show a STOCK of -2. That's why you need the CHECK constraint that Kevin suggested
ALTER TABLE products
ADD CONSTRAINT chk_positive_stock CHECK( stock >= 0 );

Resources