Mysql compare rows same table then add another table - mysql

i have a mysql products table like that;
http://www.sqlfiddle.com/#!9/56ac8e/2
when each line is added, I want it to compare with the latest price of the same coded product. if it is cheaper than the latest price, I want it to add rows to another table in the following way.
discount table is ;
http://www.sqlfiddle.com/#!9/c2227d/1
i changed the codes in the form of the link below, but it didn't work.
Compare rows in same table in mysql
CREATE DEFINER = CURRENT_USER TRIGGER `database`.`products_AFTER_INSERT` AFTER INSERT ON `products` FOR EACH ROW
BEGIN
WHERE NEW.product_id = OLD.product_id
IF NEW.price < OLD.price
THEN
INSERT INTO discount
(
id (auto) ,
product_id,
name ,
old.price ,
new.price ,
discount ((old.price / new.price )/10)
);
END IF;
END$$
can you help me in this regard ?

Solved. Akina Thank You..
https://dbfiddle.uk/fbeR9LTE
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id CHAR(7),
name VARCHAR(255),
price DECIMAL(10, 2),
`date` DATETIME,
url VARCHAR(768)
);
CREATE TABLE discount (
product_id CHAR(7) PRIMARY KEY,
name varchar(255),
old_price DECIMAL(10, 2),
new_price DECIMAL(10, 2),
discount DECIMAL(3, 2),
url VARCHAR(768)
);
CREATE TRIGGER tr_bi_discount
BEFORE INSERT ON products
FOR EACH ROW
BEGIN
DECLARE prev_price DECIMAL(10, 2);
SELECT price INTO prev_price FROM products WHERE product_id = NEW.product_id ORDER BY `date` DESC LIMIT 1;
IF NEW.price < prev_price THEN
REPLACE INTO discount
SELECT NEW.product_id, NEW.name, prev_price, NEW.price, 1 - NEW.price / prev_price, NEW.url;
END IF;
END
INSERT INTO products (product_id, name, price, `date`, url) VALUES
('AD12CDS', 'iphone 13', 790.00, '2022-09-13 15:05', 'https://www.abcde.com.tr/1'),
('DDSC22S', 'samsung s22', 989.00, '2022-09-14 15:05', 'https://www.abcde.com.tr/2'),
('SDX10XA', 'xioami a10', 540.00, '2022-09-15 15:05', 'https://www.abcde.com.tr/3'),
('SDX10XA', 'xioami a10', 539.00, '2022-09-16 15:05', 'https://www.abcde.com.tr/4'),
('DDSC22S', 'samsung s22', 990.00, '2022-09-17 15:05', 'https://www.abcde.com.tr/5'),
('DDSC22S', 'samsung s22', 800.00, '2022-09-18 15:05', 'https://www.abcde.com.tr/6'),
('AD12CDS', 'iphone 13', 800.00, '2022-09-19 15:05', 'https://www.abcde.com.tr/7'),
('AD12CDS', 'iphone 13', 600.00, '2022-09-20 15:05', 'https://www.abcde.com.tr/8'),
('AA11SDE', 'ipnone 12', 500.00, '2022-09-21 15:05', 'https://www.abcde.com.tr/9'),
('DFR12SD', 'samsung s20', 400.00, '2022-09-22 15:05', 'https://www.abcde.com.tr/10');
SELECT * FROM products;
SELECT * FROM discount;

Related

Tracking Increasing or decreasing prices in MySQL

I tried to write a query that returns the id, product, price, and change columns. The change column should follow this logic. If the item price has increased it should write positive and if it has decreased negative depending on the product and excluding the first initial product price. The last product price should be taken into consideration.
This is how the result should look like.
id product price change
1 apple 1
2 apple 1.5 positive
3 apple 3 positive
4 melon 4
5 melon 3 negative
6 apple 2 negative
I have tried to use Case When statement but failed.
select
p.id,
p.product,
p.price,
CASE
WHEN p.product = p.product AND p.price > p.price THEN 'Positive'
WHEN p.product = p.product AND p.price > p.price THEN 'Negative'
END AS 'Change'
from products p
Create and insert statements
CREATE TABLE `products` (
`id` INT(11) NOT NULL,
`product` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`price` DECIMAL(10,2) NOT NULL DEFAULT '0.00'
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;
INSERT INTO products (id, product, price)
VALUES (1, 'apple', 1);
INSERT INTO products (id, product, price)
VALUES (2, 'apple', 1.5);
INSERT INTO products (id, product, price)
VALUES (3, 'apple', 3);
INSERT INTO products (id, product, price)
VALUES (4, 'melon', 4);
INSERT INTO products (id, product, price)
VALUES (5, 'melon', 3);
INSERT INTO products (id, product, price)
VALUES (6, 'apple', 2);
Use lag():
select p.*,
(case when lag(price) over (partition by product order by id) < price
then 'negative'
when lag(price) over (partition by product order by id) > price
then 'positive'
end)
from products p;
In archaic versions of MySQL, you can use a correlated subquery:
select p.*
(case when prev_price < price
then 'negative'
when prev_price > price
then 'positive'
end)
from (select p.*,
(select p2.price
from product p2
where p2.product = p.product and p2.id < p.id
order by p2.id desc
limit 1
) as prev_price
from product p
) p;

Tricky sql query required, finding a sum of a subquery

A relevant part of my db looks as follows (MS Visio, I know I'm pathetic :D):
I need to extract a list consisting of all items in a category as well as bundles. So I have to use UNION. First part of a UNION for your reference (as it sets the data format for the SELECT in the second part of UNION; note that ? signifies where an argument goes in node-mysql):
SELECT `ID`, `Name`, `Description`,
`PictureID`, `SellingPrice`,
`Cost`, 0 AS `Bundle`
FROM `Item`
WHERE `CategoryID`=? AND
`ID` IN (
SELECT `ItemID`
FROM `Stock`
WHERE `CityID`=?
AND `IsLimitless`=1 OR `Quantity`>0
)
So I want to present my Bundles as if they are also items, with all same fields etc.
My attempt:
SELECT `ID`, `Name`, `Description`, `PictureID`,
(
SELECT SUM( // Here SQL indicates a syntax problem
SELECT `ItemAmount`*`PriceModifier`*(
SELECT `SellingPrice`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
)
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
)
) AS `SellingPrice`,
(
SELECT SUM(
SELECT `ItemAmount`*(
SELECT `Cost`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
)
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
)
) AS `Cost`,
1 AS `Bundle`
FROM `Bundle`
WHERE `ID` IN (
SELECT `BundleID`
FROM `BundleCategory`
WHERE `CategoryID`=?
)
//No need to check bundles for stock due to business logic
I have a faint idea that I'm overcomplicating this, but I can't put my finger on it, unfortunately.
Any advise will be very welcome and thanks in advance for taking your time. <3
Sample data:
Fields of no interest like "Description"/"PictureID"/"SupplierID" will be omitted
for the relevant parts to fit on screen
**Bundle**
ID Name Description PictureID
1 Valentine Pack Blah-blah tasty buy me imgur link in text
**Item**
ID Name SellingPrice Cost CategoryID
1 Movie Ticket 10 2 24
2 Box of Chocolates 5 1 4
3 Teddy Bear 15 3 2
4 Roses 10 4 8
**Stock**
ItemID CityID Quantity IsLimitLess
1 1 25 false
1 2 11 false
2 1 84 false
3 1 33 false
4 1 1 true
4 3 1 true
**BundleItem**
BundleID ItemID ItemAmount PriceModifier
1 1 2 1.25
1 2 1 1
1 3 1 1
1 4 5 0.75
**BundleCategory** (bundle for marketing reasons can appear in different
categories depending on its contents)
BundleID CategoryID
1 4 //Sweets
1 2 //Toys
1 8 //Flowers
Desired output: (For searching CityID 1, CategoryID 8, Flowers)
ID Name (Descr/PicID) SellingPrice Cost Bundle
4 Roses 10 4 false
1 Valentine Pack 82.5 28 true
/*2*10*1.25+ 2*2+ <movie
1*1*5+ 1*1+ <chocolate
1*1*15+ 3*1+ <teddy bear
5*0.75*10 5*4 <roses */
User suggested solutions
As per #drakin8564 's suggestion I tried doing
SELECT `ID`, `Name`, `Description`, `PictureID`,
(
SELECT SUM((
SELECT `ItemAmount`*`PriceModifier`*(
SELECT `SellingPrice`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
)
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
))
) AS `SellingPrice`,
(
SELECT SUM((
SELECT `ItemAmount`*(
SELECT `Cost`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
)
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`
))
) AS `Cost`,
1 AS `Bundle`
FROM `Bundle`
WHERE `ID` IN (
SELECT `BundleID`
FROM `BundleCategory`
WHERE `CategoryID`=8
)
Returns
(1242): Subquery returns more than 1 row.
This happens even when I try SELECT SUM((SELECT ID FROM Item)). Weird.
I commented on other solutions about how good they work. I appreciate all you guys taking part in this. <3
It looks like you had a few syntax issues. Your code worked with a few changes. See comments in query for details.
http://sqlfiddle.com/#!9/ee0725/16
SELECT `ID`, `Name`, `Description`, `PictureID`,
(SELECT SUM(`ItemAmount`*`PriceModifier`*( -- changed order of SELECT and SUM; removed extra SELECT; fixed Parens
SELECT `SellingPrice`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
))
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`)
AS `SellingPrice`,
(SELECT SUM(`ItemAmount`*( -- changed order of SELECT and SUM; removed extra SELECT; fixed Parens
SELECT `Cost`
FROM `Item`
WHERE `ID`=`BundleItem`.`ItemID`
))
FROM `BundleItem` WHERE `BundleID`=`Bundle`.`ID`)
AS `Cost`,
1 AS `Bundle`
FROM `Bundle`
WHERE `ID` IN (
SELECT `BundleID`
FROM `BundleCategory`
WHERE `CategoryID`=8
);
Something like this should work
SELECT tb.`ID`, MAX(tb.`Name`), MAX(tb.`Description`), MAX(tb.`PictureID`),
SUM(`ItemAmount`*`PriceModifier`*`SellingPrice`) AS `SellingPrice`,
SUM(`ItemAmount`*`Cost`) AS `Cost`,
1 AS `Bundle`
FROM `Bundle` tb
JOIN `BundleItem` tbi on tb.ID=tbi.BundleID
JOIN `Item` ti on tbi.ItemID=ti.ID
WHERE tb.`ID` IN (
SELECT `BundleID`
FROM `BundleCategory`
WHERE `CategoryID`=?
)
GROUP BY tb.ID
//No need to check bundles for stock due to business logic
Your syntax error is because your subquery is not wrapped in (). Examples below.
This will fail:
SELECT SUM(SELECT 1);
This will work:
SELECT SUM((SELECT 1));
Assumption #1: All items must have enough stock in a city for a bundle to be available in that city. (See query comments for how to remove this business rule)
In the sample data, there are no bundles that are fully in stock in any cities - to remedy this, I changed the Quanity for ItemID=4 in CityID=1 from "1" to "5". This created your desired output.
Assumption #2: Stock.Quantity=0 is allowed.
This solution produces query results that contain all Items and Bundles for every City and Category where the Item or Bundle is in stock. The where clause at the bottom filters it to CityID=1 and Category=8 per the original request.
Note: You can paste the Solution and Schema below into www.sqlfiddle.com and see the results.
UPDATE
Fixed BundleCategory join.
Solution
select * from (
select
Stock.CityID,
Item.CategoryID,
Item.ID,
Item.Name,
Item.Description,
Item.SellingPrice,
Item.Cost,
'false' as Bundle
from Item
inner join Stock on Stock.ItemID = Item.ID
where IFNULL(Stock.Quantity,0) > 0 -- remove this to show out of stock items
union
select
BundleSummary.CityID,
BundleCategory.CategoryID,
Bundle.ID,
Bundle.Name,
Bundle.Description,
BundleSummary.SellingPrice as SellingPrice,
BundleSummary.Cost as Cost,
'true' as Bundle
from Bundle
inner join (
select
BundleItem.BundleID,
City.CityID,
MIN(IF(IFNULL(Stock.Quantity, 0) < BundleItem.ItemAmount, 0, 1)) as InStock,
SUM(Item.SellingPrice * BundleItem.ItemAmount * BundleItem.PriceModifier) as SellingPrice,
SUM(Item.Cost * BundleItem.ItemAmount) as Cost
from BundleItem
inner join Item on Item.ID = BundleItem.ItemID
inner join (select distinct CityID from Stock where CityID IS NOT NULL) as City on 1=1
left join Stock on Stock.ItemID = Item.ID and Stock.CityID = City.CityID
group by BundleItem.BundleID, City.CityID
) as BundleSummary on BundleSummary.BundleID = Bundle.ID
inner join BundleCategory on BundleCategory.BundleID = Bundle.ID
where BundleSummary.InStock = 1 -- remove this to show out of stock bundles
) as qry1
where CityID=1 and CategoryID=8;
I also generated a script to create the database schema and populate it with the sample data. Thought this might be helpful to anyone who is using this solution to investigate their own issues.
Schema
create table Item (
ID int,
Name varchar(255),
Description varchar(255),
PictureID int,
SellingPrice DECIMAL(12,4),
Cost DECIMAL(12,4),
SupplierID int,
CategoryID int
);
insert into Item values (1, 'Movie Ticket', '', NULL, 10, 2, NULL, 24);
insert into Item values (2, 'Box of Chocolates', '', NULL, 5, 1, NULL, 4);
insert into Item values (3, 'Teddy Bear', '', NULL, 15, 3, NULL, 2);
insert into Item values (4, 'Roses', '', NULL, 10, 4, NULL, 8);
create table Bundle (
ID int,
Name varchar(255),
Description varchar(255),
PictureID int
);
insert into Bundle values (1, 'Valentine Pack', 'Blah-blah tasty buy me', NULL);
create table Stock (
ItemID int,
CityID int,
Quantity int,
IsLimitless bit
);
insert into Stock values (1, 1, 25, false);
insert into Stock values (1, 2, 11, false);
insert into Stock values (2, 1, 84, false);
insert into Stock values (3, 1, 33, false);
insert into Stock values (4, 1, 5, true);
insert into Stock values (4, 3, 1, true);
create table BundleItem (
BundleID int,
ItemID int,
ItemAmount int,
PriceModifier DECIMAL(12,4)
);
insert into BundleItem values (1, 1, 2, 1.25);
insert into BundleItem values (1, 2, 1, 1);
insert into BundleItem values (1, 3, 1, 1);
insert into BundleItem values (1, 4, 5, 0.75);
create table BundleCategory (
BundleID int,
CategoryID int
);
insert into BundleCategory values (1, 4); -- Sweets
insert into BundleCategory values (1, 2); -- Toys
insert into BundleCategory values (1, 8); -- Flowers

sql select from table with date range condition

I have this table
CREATE TABLE `tarif` (
`tarif_id` int(11) NOT NULL AUTO_INCREMENT,
`start_tarif` date NOT NULL,
`end_tarif` date NOT NULL,
`day_tarif` varchar(50) NOT NULL,
PRIMARY KEY (`tarif_id`)
);
INSERT INTO `tarif` VALUES (1, '2019-02-01', '2019-02-10', '10'),
(2, '2019-02-11', '2019-02-20', '20'),
(3, '2019-02-21', '2019-02-28', '10'),
(4, '2019-03-01', '2019-02-10', '15');
How can I get day_tarif between 2019-02-05 and 2019-02-15 and calculate the sum = day_tarif * number of date betwwen 2019-02-05 and 2019-02-15
You can use the following solution using DATEDIFF:
SELECT SUM((DATEDIFF(LEAST(`end_tarif`, '2019-02-15'), GREATEST(`start_tarif`, '2019-02-05')) + 1) * `day_tarif`) AS sumCustom
FROM `tarif`
WHERE `end_tarif` >= '2019-02-05' AND `start_tarif` <= '2019-02-15'
demo on dbfiddle.uk
You can use the following solution using SUM and COUNT:
SELECT SUM(`day_tarif`) * COUNT(`tarif_id`)
FROM `tarif`
WHERE `end_tarif` >= '2019-02-05' AND `start_tarif` <= '2019-02-15'
select SUM(day_tarif) * COUNT(tarif_id)
from tarif
where end_date >= '2019-02-05' AND start_date <= '2019-02-15'
This question has been asked several times, or something like it. Be sure to search StackOverflow before asking a duplicate: SQL query to select dates between two dates
You can try following code:
WITH cte AS(
SELECT *
FROM tablename
WHERE end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15'
)
SELECT day_tarif, day_tarif * COUNT(tarif_id) AS 'SUM'
FROM cte
group by day_tarif;
I think this might be what you are after...
Declare #tarif as table (
tarif_id int NOT NULL ,
start_tarif date NOT NULL,
end_tarif date NOT NULL,
day_tarif varchar(50) NOT NULL
);
INSERT INTO #tarif VALUES (1, '2019-02-01', '2019-02-10', '10'),
(2, '2019-02-11', '2019-02-20', '20'),
(3, '2019-02-21', '2019-02-28', '10'),
(4, '2019-03-01', '2019-02-10', '15');
-- Declare parameters
Declare #paramstart date, #paramend date
Set #paramstart='2019-02-05'
Set #paramend='2019-02-15'
-- Set up loop
Declare #mincount int, #maxcount int, #myval int, #curstart date, #curend date,#curtarif int, #mytarif int
Set #mincount=(Select MIN(tarif_id) from #tarif where end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15')
Set #maxcount=(Select Max(tarif_id) from #tarif where end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15')
Set #mytarif=0
-- Do loop
WHile #mincount<=#maxcount
BEGIN
Set #curstart=(Select start_tarif from #tarif where tarif_id=#mincount)
Set #curend=(Select end_tarif from #tarif where tarif_id=#mincount)
Set #curtarif=(Select cast(day_tarif as int) from #tarif where tarif_id=#mincount)
IF #paramstart between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#paramstart,#curend)+1) * #curtarif)
END
IF #paramend between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#curstart,#paramend)+1) * #curtarif)
END
IF #paramstart not between #curstart and #curend and #paramend not between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#curstart,#curend)+1) * #curtarif)
END
Set #mincount=#mincount+1
END
Select #mytarif as tarif
Try this!
select day_tarif , sum(day_tarif * count (*)) as sum
where start_tarif between '2019/02/05' and '2019/02/15' and end_tarif between '2019/02/05' and '2019/02/15'
group by day_tarif;

MySQL insert values if condition is met

I am trying to insert into a table only if the qty has changed down in another table see example
INSERT INTO sales_items (sale_id, item_id, quantity_purchased, item_cost_price, item_unit_price)
VALUES ('1', '1546', '3', '10', '10')
WHEN (SELECT quantity FROM location_items WHERE location_id =4 AND item_id =1546) < 10;
You can do the following:
INSERT INTO sales_items
(sale_id, item_id, quantity_purchased, item_cost_price, item_unit_price)
VALUES
(SELECT '1', '1546', '3', '10', '10'
FROM location_items
WHERE location_id = 4
AND item_id = 1546
AND quantity < 10
);
Or, if you want to do it all in one query, including updates:
REPLACE INTO sales_items
(item_id, quantity_purchased, item_cost_price, item_unit_price)
VALUES
(SELECT item_id, ??, ??, ??
FROM location_items
WHERE quantity < 10
AND quantity > 0
);
...where you have to fill the ?? with references to columns holding the values for item_cost_price and item_unit_price, and you have a unique constraint on item_id
Not possible like that. An INSERT query cannot have a where clause, period.
You can, hover, do an insert select from:
INSERT INTO ...
SELECT ... FROM ... WHERE (...) < 10
If the SELECT finds no rows, then nothing gets inserted.

SQL Query To Show Total Each Time SalesMan Changes

This is my table structure with garbage data inserted. What I am wanting to do is for each sales man (Frank and Joe) have a total row underneath them. This is how I want the data to display when returned form my query
This is table structure filled with garbage data, can someone assist me on how to set this up?
Create Table TurribleSetUp
(
ID int,
si varchar(200),
salesmanname varchar(50),
itemsold varchar(100)
)
Insert Into TurribleSetUp Values
(1, 'Home Frank Bad', 'Frank', 'stove'),
(2, 'Internet Frank Left', 'Frank', 'table'),
(3, 'Store Frank Total Store Card', 'Frank', 'stereo')
,(4, 'Store Joe Bad', 'Joe', 'stove'),
(5, 'Store Joe Right', 'Joe', 'stove'),
(6, 'Joe, Person, High Five', 'Joe', 'car')
,(7, 'Frank, Person, High Five', 'Frank', 'car'),
(8, 'Left, Low Five, Joe', 'Joe', 'car')
Try;
select info, total_sale, itemsold piece_of_equipment_sold
from (
select si info, count(itemsold) total_sale, itemsold, salesmanname
from TurribleSetUp
group by si, itemsold, salesmanname
union all
select 'Total for ' + salesmanname, count(itemsold), '' , salesmanname
from TurribleSetUp
group by salesmanname
) x
order by salesmanname, total_sale
I'd do something like this:
select ts.salesmanname, si, count(itemsold) as Cnt, itemsold
from TurribleSetUp ts
group by si, itemsold, ts.salesmanname
union
select salesmanname, 'Totals For '+ Salesmanname as si, count(itemsold) as Cnt, NULL as itemsold
from TurribleSetUp
group by salesmanname
order by ts.salesmanname
I ordered it by Salesman Name. I'm assuming you have some type of number that you'd order it by instead.