Select groups of row only having specific value? - mysql

I want to select rows of products group by product_group_id that only have is_shown = 1.
Product Table
+----+------------------+---------+----------+
| id | product_group_id | name | is_shown |
+----+------------------+---------+----------+
| 1 | 1 | apple | 1 |
| 2 | 1 | orange | 1 |
| 3 | 1 | kiwi | 0 |
| 4 | 2 | table | 1 |
+----+------------------+---------+----------+
My sql statement is
SELECT * FROM product WHERE is_shown = 1 GROUP BY product_group_id
What I need is a rows that only have is_shown = 1.
So My expected result is I will only get a row
Product Table
+----+------------------+---------+----------+
| id | product_group_id | name | is_shown |
+----+------------------+---------+----------+
| 4 | 2 | table | 1 |
+----+------------------+---------+----------+
Buy I still get a product_group_id = 1.
Please help. Thanks

Then just exclude them:
SELECT
*
FROM
Product
WHERE
product_group_id NOT IN (
SELECT
product_group_id
FROM
Product
WHERE
is_shown = 0
)
Select all products except that product_group_id, that have is_shown =0.

Hope it Helpful...
SELECT
*
FROM
Product
WHERE
product_group_id NOT IN (
SELECT
product_group_id
FROM
Product
WHERE
is_shown != 1
)
GROUP BY
product_group_id

You can use subquery for this.
Get all the product_group_id and use it to filter rows.
SELECT
*
FROM
Products
WHERE
product_group_id IN
(
SELECT
product_group_id
FROM
Products
GROUP BY
product_group_id
HAVING
min(is_shown) = 1
)

Related

Group the records and sort groups in itself

I have 2 columns in my pricing table: car_id and price
I want to
Group the records with same car_ids and sort these groups by price in itself. (namely, all records with the same car_id must be listed consecutively.)
I want to sort these groups by minimum price they include.
For example,
car_id | price
---------------
1 | 2
1 | 5
2 | 3
2 | 1
2 | 10
3 | 7
3 | 3
3 | 8
should be sorted like this:
car_id | price
---------------
2 | 1
2 | 3
2 | 10
1 | 2
1 | 5
3 | 3
3 | 7
3 | 8
How can I write a query that performs this operation? I am using MySQL V5.6.
You may use a subquery since the 5.6 does not support the window functions.
select *,
(
select min(price)
from datatab d2
where d1.car_id = d2.car_id
) min_price
from datatab d1
order by min_price, car_id, price
DBFIDDLE DEMO
You can use a subquery that returns the min price for each car_id in the ORDER BY clause:
select t.*
from tablename t
order by
(select min(price) from tablename where car_id = t.car_id),
car_id,
price
See the demo.
Or join the table to the subquery that returns all the min prices:
select t.*
from tablename t inner join (
select car_id, min(price) minprice
from tablename
group by car_id
) m on m.car_id = t.car_id
order by
m.minprice,
t.car_id,
t.price
See the demo.
Results:
| car_id | price |
| ------ | ----- |
| 2 | 1 |
| 2 | 3 |
| 2 | 10 |
| 1 | 2 |
| 1 | 5 |
| 3 | 3 |
| 3 | 7 |
| 3 | 8 |
You can use window functions in the order by:
select p.*
from pricing p
order by min(price) over (partition by car_id),
car_id;
The car_id handles the case when multiple car_ids have the same minimum price.
In older versions of MySQL, you can do something similar with a subquery:
select p.*
from pricing p
order by (select min(p2.price) from pricing p2 where p2.car_id = p.car_id),
car_id;

How to calculate max values of groups?

I have a table like so (I'm not sure how to format tables)
Category / Products / Purchases
1 | A | 12
1 | B | 13
1 | C | 11
2 | A | 1
2 | B | 2
2 | C | 3
Expected output:
1 | B | 13
2 | C | 3
However I keep on getting
1 | A | 13
2 | A | 3
ie. It just selects the first occurrence of the second column.
Here is my code:
SELECT Category, Products, MAX(Purchases) FROM myTable GROUP BY Category;
Use filtering in the where clause:
select t.*
from t
where t.purchases = (select max(t2.purchases) from t t2 where t2.category = t.category);
With NOT EXISTS:
select m.* from myTable m
where not exists (
select 1 from myTable
where category = m.category and purchases > m.purchases
)
See the demo.
Results:
| Category | Products | Purchases |
| -------- | -------- | --------- |
| 1 | B | 13 |
| 2 | C | 3 |
You can use row_number() to identify max purchase for each group or replace rownumber() to rank() if there are ties of max purchases for each group
Select Category, Products,
Purchases from (Select Category,
Products,
Purchases,
row_number() over (partition by
category, products order by
purchases desc) rn from table) t
where t.rn=1
)

Control the row returned on a group by that matches the result

I have the following table:
----------------------------
| id | product | price |
----------------------------
| 1 | 1 | 50 |
| 2 | 1 | 39 |
| 3 | 1 | 60 |
----------------------------
What I need is to get the lowest price (39) grouped by product (1) and keep the id of the lowest price.
I have this query
SELECT
id,
product,
MIN(price) AS price
FROM
variant
GROUP BY
product
That results on
----------------------------
| id | product | price |
----------------------------
| 1 | 1 | 39 |
----------------------------
But the result I'm looking for is
----------------------------
| id | product | price |
----------------------------
| 2 | 1 | 39 |
----------------------------
Is it possible to achieve this?
I've made a fiddle: http://sqlfiddle.com/#!9/d2ddb2
try: (not very elegant but a good platform to make further changes)
select A.*,B.id from
(SELECT product,MIN(price) AS minprice
FROM variant GROUP BY product ) A
inner join
(SELECT * FROM variant ) B
on A.product = B.product and A.minprice = B.price
You could divide the id by x (like 1000000 depending on limit of id) and add it to the price. Then take the min and split out the id later. It's kinda backwoods but should work.
SELECT
product,
MIN(price+(id/10000)) AS price
FROM
variant
GROUP BY
product

using HAVING to filter results based on a reference row

I have the following table:
+---------+--------------+----------+
| item_id | location_id | price |
+---------+--------------+----------+
| 1 | 1 | 100 |
| 1 | 1 | 250 |
| 1 | 2 | 50 |
| 2 | 1 | 250 |
| 2 | 1 | 1000 |
| 3 | 1 | 1000 |
| 3 | 2 | 100 |
+---------+--------------+----------+
I can reduce this down to the minimum values using this query
SELECT
item_id, location_id, MIN(price) AS Price
from
table
GROUP BY item_id , location_id
This gets me
+---------+--------------+----------+
| item_id | location_id | price |
+---------+--------------+----------+
| 1 | 1 | 100 |
| 1 | 2 | 50 |
| 2 | 1 | 250 |
| 3 | 1 | 1000 |
| 3 | 2 | 100 |
+---------+--------------+----------+
I want to reduce this further. I am using the rows with a location_id of 1 as a reference row. For each row that has an item_id matching the reference row's item_id but a different location id. I want to compare that row's price with the reference row's price. If the price is lower than the reference row's price, I want to filter that row out.
My final result should include the reference row for each item id and any rows that met the criteria of the price being lower than the reference row price.
I have a hunch that I can use the HAVING clause to do this but I am having trouble compiling the statement. How should I construct the HAVING statement?
Thanks in advance
Nah, having can't help you like this, having is for things like you need filter min() result for something
e.g:
select id,min(price) from table where date = '2016-3-18' group by id having min(price) = 50
it will show you the records that min(price)=50
let's back to your case, there are lots of way to do that,
1. left join
select a.item_id,a.location_id,a.price
from table a
left join table b
on a.location_id = b.location_id and a.price > b.price
where b.price is null
2. exists
select a.item_id,a.location_id,a.price
from table a
where exists(
select 1 from
(select location_id,min(price)as price from table group by location_id)b
where a.location_id = b.location_id and a.price = b.price
)
normally i ll recommand you use exists

Mysql query with multiple conditions on FK

I have slight problem with mysql query. I have two tables:
bioshops
+------------+-------------+
| bioshop_id | name |
+------------+-------------+
| 1 | Bioshop1 |
| 2 | Bioshop2 |
+------------+-------------+
bioshop_have_product
+----+-----------------+--------------+
| id | bioshop_id | product_id |
+----+-----------------+--------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 3 |
+----+-----------------+--------------+
The tables are much more complex but this is the important structure. prodict_id in bioshop_have_product is also FK. I need to select bioshops witch contains all products that I ask. Example:
if I need bioshops with product 1 it should return Bioshop1 and Bioshop2 with all products
if I need bioshops with product 1 and 2 it should return Bioshop1 with all products
My query is:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshd.id AS id,
bshd.product_id AS product_id
FROM bioshops bs
JOIN bioshop_have_product bshp
ON bs.bioshop_id = bshp.bioshop_id
WHERE (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '1')
AND (bshp.bioshop_id = bs.bioshop_id AND bshp.product_id = '2')
but this returns nothing and I want it to return Bioshop1 because only Bioshop1 countains both objects.
You can try something like this:
SELECT bs.name AS name,
bs.id AS bioshop_id,
bshp.id AS id,
bshp.product_id AS product_id
FROM bioshop bs
JOIN bioshop_have_product bshp
ON bs.id = bshp.bioshop_id AND
(SELECT COUNT(*) FROM bioshop_have_product WHERE product_id IN (1, 2) AND bs.id = bioshop_id) = X
where X should be equal to the count of different products you whant to check, for instance 2 in your second case.
SELECT bioshop_id
FROM bioshop_have_product
WHERE product_id IN (1,2)
GROUP
BY bioshop_id
HAVING COUNT(*) = 2;