Trigger to decrease a counter - mysql

I want to create a trigger to decrease the quantity of available items after an order has been made.
I tried to create a trigger. I'm using phpMyAdmin, setting trigger AFTER INSERT in the table products_in_order
SET #qtt = (
SELECT quantity
FROM products_in_order
ORDER BY inorder_id DESC
LIMIT 1)
SET #code = (
SELECT product_code
FROM products_in_order
ORDER BY inorder_id DESC
LIMIT 1)
UPDATE products
SET quantity = quantity-#qtt
WHERE product_code=#code
Why does the first SET work, and the second, too, but as soon as I write them both, i get an error?
How to make this trigger work correctly?
Sample data:
products represents all products available in the shop, and has columns:
product_code | name | price | quantity
product_in_order represents a set of products of the same type, that can be added to order. It has colums:
inorder_id | product_code | price | order_no
inorder_id | product_code | price | quantity | order_no
When somebody adds a set of products to the order, I want the overall quantity of that product to decrease.

You don't need to join back to the newly inserted / updated table* - just use the New pseudo row from within your trigger, which already has the values you need to join into the master Product table:
CREATE TRIGGER `MyTrigger`
AFTER INSERT ON `products_in_order`
FOR EACH ROW
BEGIN
UPDATE products
SET quantity = quantity-New.quantity
WHERE product_code=New.product_code;
END;
SqlFiddle here demonstrating that the starting value of Product is depleted by the amount inserted into products_in_order for the applicable product code.
* Assuming inorder_id is an AUTO_INCREMENT, selecting from this table twice without any locking considerations will also be prone to concurrency issues, e.g. if another writer inserts another row while your trigger is executing. Another good reason to use New

Related

MySQL Update Table WHERE column in another is

I have two tables in MySQL and I would like to update a column in one of them to match values from another.
The tables each have a customer and part number column.
Table 1:
Customer_Name | Part_Number | Demand | Allocation
Table 2:
Customer_Name | Part_Number | Demand
I want to update table 1 to add table 2 demand to the allocation figure in table 1, if the part number and customer both exist in table 2.
A query I have attempted so far:
UPDATE `Packing_Dispatch` SET Allocation = `Packing_Allocation`.Demand WHERE
Customer_Name = `Packing_Allocation`.Customer_Name AND Part_Number = `Packing_Allocation`.Part_Number
How can I do this?
You can try below
UPDATE `Packing_Dispatch`
Join `Packing_Allocation`
SET Allocation = `Packing_Allocation`.Demand
WHERE Customer_Name = `Packing_Allocation`.Customer_Name AND Part_Number = `Packing_Allocation`.Part_Number

Need to archive data on successful cart transaction using Update SQL JOIN

I need to archive a product when it has been bought in the storefront. I`m thinking about doing a SQL JOIN but not sure...
Is this the query I need to run?
UPDATE product
INNER JOIN cart on cart.product_id = product.id
SET product.archive = 1
cart
id (int)
product_id (int)
quantity (int)
product
id (int)
name (varchar 45)
price (decimal 10,2)
quantity (int)
image (varchar 255)
archive (tinyint) default 0
That seems like a situation where you'd you want to use a trigger. Everytime a new line is added in the Cart table, it should update product.archive to 1 (or any other changes to the Product table).
DELIMITER $$
CREATE TRIGGER tg
AFTER INSERT ON Cart
FOR EACH ROW
BEGIN
UPDATE Product
SET archive = 1
WHERE Product.id = NEW.product_id;
END $$
Please take into account that I'm new to MySQL and I'm not sure if this is the right way to do this.
The update query
Let's examine this query closely
UPDATE product
INNER JOIN cart on cart.product_id = product.id
SET product.archive = 1
What does this query do? It archives every single product that has been placed into at least one user's cart. Surely that's not what you want? Your cart table does not have a user id in it. HOw do you determine which item in the cart belong to which user? Please consider adding such a column to your table.
To archive or not to archive
Shouldn't a product be archived only when it's quantity reaches zero? but should it be archived at all? If you have an archive column in your table in each query you will need to have a clause that checks this flag
SELECT * FROM product WHERE archive = 1 /* or 0 */
But this archive column can take only one of two values and that makes an index on that column completely useless. So as your data grows, your queries will become slower and slower.

Mysql : insert into select && where not exists

I need to insert some data in a table named ‘queue’ which is a patient queue in a particular date . Two fields data will be inserted .Two fields name are ‘PatientID’ and ‘Visiting Date’. Table ‘queue' like
QueueID | PatientID | Visiting_date |
-------------|-------------------|-------------------------|
1 | 4 | Current date |
table:queue
But while inserting the record there are two conditions :
Condition 1 : patitentID comes from patient table (given below)
Condition 2 : one record will be inserted to ‘queue’ table if it does not exist to prevent repeatation.ie PatientID=4 will not be inserted if already inserted.
-------------|-----------------|------------------|
patitentID | Patient Name | Contact no |
-------------|-----------------|------------------|
4 | David | 01245785874 |
table:patient
My SQL is: (it does not work)
INSERT INTO `queue`(`patientID`, `Visiting_date`)
SELECT patient.`patientID`,’CURDATE()’ FROM `patient`
WHERE NOT EXISTS (
SELECT `patientID`, `visiting_date`FROM `queue`
WHERE `patientID` = '4' AND `visting_date`=CURDATE()
) LIMIT 1;
You could set a foreign key to make sure the patients id exists.
In the Queue table you can set patientID as unique, this makes sure you can insert only unique id's in the queue table.
Also if you would like to be able to insert the same userID but with different dates you could specify unique constraint for multiple columns in MySQL.
If you want to solve it with a mysql query only you can use this question.
I would use a separate query to check if there is a user with that ID in that table.
SELECT * FROM queue WHERE PatientID = 4;
and then check the result of that query, if it returns a row, that means that there is a user in there and you don't do anything.
If the query doesn't return a row, that means you can now use a query to inert a user. Like this
INSERT INTO queue (PatientID, VisitingDate);

Change a field with a sum value to individual entries

I have a table for rating an item.
The field rating holds a numeric value that I used to simply increase.
This method has its upsides but the downside is, that I can't have a rating of the past month/30 days because I don't have the individual ratings.
How would I go through the table, check if the ratingvalue is higher than 1 and if so add a new line for each rating?
eg
The table now
id | item_id | rating
1 | 2198 | 42
So I would like to have 42 individual entries.
Question:
Can I do this with only mysql if so how?
You need a stored procedure to do it, but you can do it in mysql.
Since you didn't add your table definitions I will assume id is an auto_increment key and that you don't want to preserve your original values.
Otherwise change the key or use a new (temporary) table with an auto_increment key.
DELIMITER $$
drop PROCEDURE if exists individualizemytable $$
CREATE PROCEDURE individualizemytable()
BEGIN
while (select count(*) from TheTable where rating > 1) do
insert into TheTable (item_id, rating)
select item_id, 1
from TheTable where rating > 1;
update TheTable
set rating = rating - 1
where rating > 1;
end while;
end $$
DELIMITER ;
call individualizemytable();
Simply use INSERT for each time rather than UPDATE while adding rating to an item. Also use current timestamp for the entry.
This will allow you to sum up ratings for an item between two dates easily.
Other but some lengthy solution would be UPDATE the rating count each time for an item and add last modified timestamp.
While updating, you can compare month from last modified timestamp and the current month. If they are the same the you can do UPDATE and if they are different, you will do INSERT. This way you can have direct count of total ratings for an item for all the months individually.
But again this method will have deep checking like comparing year, also it will impose extra overheads for fetching last modified timestamp every time etc.

MySQL set default field value on delete

I have a problem with my query. I have 2 tables with relationship.
table category
CategoryId name
1 category1
2 category2
table order
orderId CategoryId date Description
1 2 2014-10-10 okay
2 1 2014-10-10 okay2
3 1 2014-10-10 okay3
my question is how to set categoryname if one of category have deleted.
The most important question here is about the business logic. Does an order without a category make sense? If yes, then you can set the categoryId to null in the orders table when a category is deleted. You can use triggers for that.
However a better solution would be to add enabled column to your category and instead of deleting a category simply set its enabled to false - this makes it unavailable for further selection yet preserves the previous information/relationship. Of course, this would require a small change in the place where the categories are selected for presentation, namely adding where enabled=true to the query.
If you're set on deleting the category and settings category ID to null in the orders, then the syntax you're looking for is
DELIMITER //
CREATE TRIGGER category_before_delete
BEFORE DELETE ON category FOR EACH ROW
BEGIN
UPDATE `order` SET categoryid=null WHERE categoryid=OLD.categoryid;
END; //
DELIMITER ;