I would like to query related data from an additional table, where I am able to get the lowest associated value...
Example of two tables
products
id name description
0 product_1 short description of 1
1 product_2 short description of 2
prices
id product_id option price personal
0 1 3 10.00 1
1 0 2 15.00 1
2 1 3 5.00 0
3 1 3 8.00 0
4 0 2 7.00 1
Output needed
id name description price option
0 product_1 short ... 7.00 2
1 product_2 short ... 10.00 3
The query I am basically attempting to make is one which gets all associated fields, gets the associated data from prices where personal = 1 and has the lowest price.
Current query (getting lowest price but not associated option)
SELECT products.*, prices.option,
(SELECT ROUND( MIN( price ), 2) FROM prices WHERE product_id = products.id AND personal = 1) AS price
FROM products
ORDER BY price_low ASC
What about using a join instead of a subquery and grouping by products? It should look something like this:
SELECT products.*, ROUND(MIN(prices.price), 2), prices.option
FROM products
INNER JOIN prices ON products.id = prices.product_id
WHERE prices.personal = 1
GROUP BY products.id
I tried it out on SqlFiddle, here are the results.
you could use an inner join and a subselect with and group by for get the min price
SELECT p.id, p.name, p.description, pr.option, pr.price
FROM products as p
inner join (
select product_id, min(price) as price
from price
where personal = 1
group by product_id
) t on t.product_id= p.id
inner join price as pr on pr.product_id = p.id and pr.price = t.price
where pr.personal =1
group by p.id, p.name, p.description, pr.option
ORDER BY pr.price ASC
Thank you for the feedback on this question. After a lot of trail and error I finally got the needed result, here it is:
SELECT products.*, b.*, products.id as id FROM `products`
LEFT JOIN
(SELECT * FROM
( SELECT * FROM prices ORDER BY product_id ASC, price ASC )
as c GROUP BY product_id)
AS b ON b.product_id = products.id
WHERE `price` IS NOT NULL ORDER BY `product_id` ASC
Related
i have 2 tables (mysql)
tbl_products
tbl_counting
I have collected "rack" & "stock" information by 3 users in tbl_counting table.
I want to update "tbl_products.rack" & "tbl_products.stock" with tbl_counting data
with this condition (like Result):
Each "Rack" & "Stock" information must be collected by at least 3 users
tbl_products.rack" & "tbl_products.stock" must update with highest frequency (At least 2 times) of "Rack" or "Stock" information
If "Rack" or "Stock" information was repeated less than 2 times, specify field with "Unknow". (like result)
Thanks
1. tbl_products (befor update)
id
product_name
rack
stock
1
apple
2
orange
3
strawberry
2. tbl_counting
product_id
user_id
rack
stock
1
1
A-1-1
20
1
2
A-1-1
10
1
3
B-1-1
20
2
1
C-1-1
10
2
2
D-2-1
30
2
3
A-3-1
30
3
1
X-3-1
25
3
2
X-1-1
10
3
3
X-3-1
25
Result: tbl_products(after UPDATE)
id
product_name
rack
stock
1
apple
A-1-1
20
2
orange
Unknown
30
3
strawberry
X-3-1
25
select
tbl_counting.product_id,
tbl_counting.rack,
MAX(tbl_counting.stock),
count(*) as freq
from tbl_counting
group by tbl_counting.product_id
having count(*) =(select max(freq)
from (select product_id,count(*) as freq
from tbl_counting group by product_id) tbl_counting)
You Can check this
SELECT
product_id p,
shelf,
floor,
line,
stock
FROM
user_product
GROUP BY
product_id,
stock,
floor,
line,
shelf
HAVING
stock = ( SELECT stock FROM user_product WHERE product_id = p GROUP BY stock ORDER BY count(*) DESC LIMIT 1 ) AND
floor = ( SELECT floor FROM user_product WHERE product_id = p GROUP BY floor ORDER BY count(*) DESC LIMIT 1 ) AND
line = ( SELECT line FROM user_product WHERE product_id = p GROUP BY line ORDER BY count(*) DESC LIMIT 1 ) AND
shelf = ( SELECT shelf FROM user_product WHERE product_id = p GROUP BY shelf ORDER BY count(*) DESC LIMIT 1 );
Here is one possible solution. The first two cte gets you the count of users and distinct racks by product, which are used in the next cte to filter the records that meet the given criteria.
UPDATE tbl_products P
JOIN (
WITH uses_count AS
(
SELECT product_id,
COUNT(DISTINCT user_id) AS num_users
FROM tbl_counting
GROUP BY product_id
)
, rack_count AS
(
SELECT product_id,
rack,
COUNT(*) AS freq
FROM tbl_counting
GROUP BY product_id, rack
)
,rank_result AS
(
SELECT T.product_id,
T.rack,
T.stock,
R.freq,
U.num_users,
ROW_NUMBER() OVER(PARTITION BY T.product_id ORDER BY R.freq DESC, T.stock DESC) AS RN
FROM tbl_counting T
LEFT JOIN uses_count U
ON T.product_id = U.product_id
AND CASE WHEN U.num_users >= 3 THEN TRUE ELSE FALSE END
LEFT JOIN rack_count R
ON T.product_id = R.product_id
AND CASE WHEN R.freq >= 2 THEN TRUE ELSE FALSE END
)
SELECT product_id,
stock,
CASE WHEN freq IS NULL THEN 'Unknown' ELSE rack END AS rack
FROM rank_result
WHERE RN = 1) R
ON P.Id = R.product_id
SET P.stock = R.stock,
P.rack = R.rack
I have items that can have many prices. I want a result table that has all the items itself and only the latest price of the item for a given region.
item
id
name
1
banana
2
apple
price
id
item_id
region
price
date
1
1
USA
10
1-1-2021
2
1
USA
20
2-1-2021
3
2
USA
30
1-1-2021
4
2
Canada
40
2-1-2021
result (should look like this)
id
name
region
price
date
1
banana
USA
20
2-1-2021
2
apple
USA
30
1-1-2021
I tried this but it returns all the rows from both tables.
select *
from item
LEFT JOIN price p on p.item_id = item.id
where p.created_at in (
select max(price.created_at)
from price
where p.id = price.id
)
and p.region = 'USA'
I fail to understand what I have to do to reduce the result table to only the rcords with the latest prices for each item.
Try this:
SELECT p.id, i.name, p.region, p.price, p.date
FROM price p
INNER JOIN (SELECT item_id, MAX(date) AS date FROM price GROUP BY item_id) t
ON t.item_id = p.item_id AND t.date = p.date
JOIN item i
ON p.item_id = i.id
WHERE p.region = 'USA'
Part of the reason your code did not work is that, in your WHERE clause, you are filtering by the maximum date of all the records in the price table.
This is a typical use-case for row_number():
select *
from item i left join
(select p.*,
row_number() over (partition by id order by created_at desc) as seqnum
from price p
where p.region = 'USA'
) p
on p.item_id = i.id and seqnum = 1;
I am joining product table with offer table using product id, my requirement is get highest offer(%) of that product, at the same time I want to make group by clause for product id because I don't want to repeat product but it is showing wrong offer id because joining query is first performed based on product id :
product table:
id name
1 abc
2 xyz
offer table
id to_date product_id offer
1 2020-12-18 1 30%
2 2020-12-18 1 40%
3 2020-12-18 2 30%
4 2020-12-18 2 40%
Query :
SELECT product_id,product.name,o.id as offer_id,o.to_date, max(o.offer)offer_price
FROM products
LEFT JOIN offers o ON o.product_id=product.id
GROUP BY product.id
Output with issue( wrong offer id):
offer_id product_id to_date offer_price
1 1 2020-12-18 40%
3 2 2020-12-18 40%
Expected output(correct offer id)
offer_id product_id to_date offer_price
2 1 2020-12-18 40%
4 2 2020-12-18 40%
You can use window functions:
select o.*, p.name as product_name
from product p
left join (
select o.*,
row_number() over(partition by product_id order by offer desc) rn
from offer o
) o on o.product_id = p.id and o.rn = 1
row_number() ranks records having the same product_id by descending offer - so the row with the greatest offer for each product gets rank 1. You can then use that information for filtering.
This requiers MySQL 8.0. In earlier versions, one alternative uses a correlated subquery to filter on the greatest offer per product:
select o.*, p.name as product_name
from product p
left join offer o
on o.product_id = p.id
and o.offer = (select max(o1.offer) from offer o1 where o1.product_id = p.id)
I have two mysql transactional tables and and two lookup tables. I want to select max(id) from each of the transactional tables, combine the results with lookup tables and combine into one row. I seem unable to find solutions so far. Here is my tables. Stocks and Prices are transactional while Vehicle and Models are lookup tables.
Vehicles table
id name
1 Toyota
2 Suzuki
Models table
id vehicle_id name
1 1 Corolla
2 2 Swift
3 1 Prado
4 2 Vitara
Stocks table
id vehicle_id model_id qty
1 1 1 50
2 2 2 77
3 1 1 40
4 2 2 30
Prices table
id vehicle_id model_id price
1 1 1 500
2 2 2 777
3 1 1 600
4 2 2 1000
Expected results
id vehicle_id model_id qty price vname mname
1 1 1 40 600 Toyota Corolla
2 2 2 30 1000 Suzuki Swift
Here is what I've tried among countless trials
select s.*, b.name vehicle, m.name model, p.price
from stocks s, vehicles b, models m, prices p
where s.id in (select max(id) id from stocks
where s.vehicle_id = b.id and s.model_id = m.id and s.vehicle_id = p.vehicle_id and s.model_id = p.model_id
group by vehicle_id, model_id)
order by id;
Running the above query doesn't give me what I want and it crushes the PC. I have to restart. How can I achieve the expected outcome?
If you are using MySQL 8 you can use window functions and common table expressions for latest(based on maximum id per vehicle and model group) prices and qty for vehicle and models
with pricescte as (select *,
rank() over (partition by vehicle_id,model_id order by id desc) AS price_rank
from prices),
stockcte as (select *,
rank() over (partition by vehicle_id,model_id order by id desc) AS stock_rank
from stocks)
select v.id,
v.name,
m.id as model_id,
m.name,
s.qty,
p.price
from vehicles v
join models m on v.id = m.vehicle_id
join stockcte s on v.id = s.vehicle_id
and m.id = s.model_id
join pricescte p on v.id = p.vehicle_id
and m.id = p.model_id
where s.stock_rank = 1
and p.price_rank = 1
DEMO
If you are not on latest version of MySQL < 8 you could use a query like
select v.id,
v.name,
m.id as model_id,
m.name,
s.qty,
p.price
from vehicles v
join models m on v.id = m.vehicle_id
join (
select *
from stocks st
where id = (
select max(id)
from stocks
where st.vehicle_id =vehicle_id
and st.model_id = model_id
)
) s
on v.id = s.vehicle_id
and m.id = s.model_id
join (
select *
from prices pr
where id = (
select max(id)
from prices
where pr.vehicle_id =vehicle_id
and pr.model_id = model_id
)
) p on v.id = p.vehicle_id
and m.id = p.model_id
DEMO
I have a peculiar problem. Given three tables.
product
- id
- title
product_rating
- product_id
- rating
product_view
- product_id
I want to grab products with a SUM of their ratings (which will either be a +1 or -1 value) and their total product count.
SELECT
p.`id`, p.`title`,
SUM( pr.`rating` ) AS rating,
COUNT( pv.`product_id` ) AS views
FROM
`product` AS p
LEFT JOIN `product_rating` AS pr ON ( pr.`product_id` = p.`id` )
LEFT JOIN `product_view` AS pv ON ( pv.`product_id` = p.`id` )
GROUP BY
p.`id`
ORDER BY rating DESC
In the table I have 1 rating, 9 views. The query, however, is returning 9 rating, 9 views. I understand why it's happening (it's summing the rating for each product_view), but I don't know how to get around it.
Any suggestions would be greatly appreciated.
Sample data:
product
------------
id | title
1 | Globber
product_rating
-------------------
product_id | rating
1 | 1
product_view
------------
product_id
1
1
1
1
1
1
1
1
1
Try
SELECT p.id, p.title, r.rating, v.views
FROM product p LEFT JOIN
(
SELECT product_id, SUM(rating) rating
FROM product_rating
GROUP BY product_id
) r ON p.id = r.product_id LEFT JOIN
(
SELECT product_id, COUNT(*) views
FROM product_view
GROUP BY product_id
) v ON p.id = v.product_id
ORDER BY r.rating DESC
Sample output:
| ID | TITLE | RATING | VIEWS |
---------------------------------
| 1 | Globber | 1 | 9 |
Here is SQLFiddle demo
How to do that?
SELECT tbl.pid,tbl.ptitle, SUM(tbl.rating) as Rate, COUNT (tbl.views) as ViewList FROM (SELECT
p.`id` as pid, p.`title` as ptitle,
pr.`rating` AS rating,
pv.`product_id` AS views
FROM
`product` AS p
LEFT JOIN `product_rating` AS pr ON ( pr.`product_id` = p.`id` )
LEFT JOIN `product_view` AS pv ON ( pv.`product_id` = p.`id` ) ) as tbl
GROUP BY
tbl.`pid`
ORDER BY tbl.Rate DESC