Select product with properties by group - mysql

Product table:
id
1
2
3
Product properties
product_id prop_id
1 1
1 2
1 3
2 2
2 3
3 1
4 2
5 1
5 3
Props has groups. Ex, prop_id (1, 2) is a group #1, prop_id (3) - group #2.
I need to select product which contains one prop from group #1 and one from group #2.
Like this
select * from product_properties WHERE prop_id IN (1, 2) AND prop_id IN (3)
But it`s doesn't work, how to create similar correct query?
That query must return me products with id 1, 2, 3.

Maybe something like this:
SELECT a.product_id, a.prop_id, b.prop_id
FROM product_properties a, product_properties b
WHERE
a.product_id=b.product_id AND
a.prop_id IN (1, 2) AND
b.prop_id = 3

SELECT product_id
FROM product_properties
GROUP BY product_id
HAVING COUNT(CASE WHEN prop_id IN (1, 2) THEN 1 END) > 0 -- mean have at least one property with 1 or 2
AND COUNT(CASE WHEN prop_id = 3 THEN 1 END) = 1 -- mean has property 3
This assume a product cant have same property more than once.

Related

how to make a complicated query

I have store table, product table and a store-product table showing their relationship.
*store table*
store_id name ...
1 store1
2 store2
3 store3
*product table*
product_id name ...
1 product1
2 product2
3 product3
*store-product table*
id store_id product_id
1 1 1
2 1 2
3 2 3
4 3 1
5 3 2
6 3 3
Once products are given, I want to get stores that are selling those products.
i.e: If the given product is 1, then stores 1, 3 should be fetched.
If the given products are 1, 2, 3, then only store 3 should be fetched.
You can use group by and having:
select sp.store_id
from store_product sp
where sp.product_id in (1, 2, 3) -- list of products
group by sp.store_id
having count(*) = 3; -- number of elements in list
Shortened table names, but something like this?
select store.name from pt
join spt on spt.product_id = pt.id
join st on spt.store_id = st.id
where st.product_id = 1

Group by different subsets of keys

I have a table of products sales
id product_id price_sold
1 1 500
2 1 300
3 2 100
4 3 200
5 3 100
I want to be able to sum the prices by different subsets of products, say: sum of prices per the group of proucts 1,2. and another calculation of sum of prices per the group of products 2,3, so the needed result will be:
group 1, 900
group 2, 400
Can you help with efficient and elegant way to do that?
Doing what you want is a bit challenging, because the groups overlap. You have two options. The first is to do conditional aggregation and put the results in columns:
select sum(case when product_id in (1, 2) then price_sold end) as group1,
sum(case when product_id in (2, 3) then price_sold end) as group2
from productsales ps;
To get the results on separate rows, you could then pivot this result. Or, you could do the calculation directly. For this to work, you need to construct a table describing the groups:
select pg.grpid, sum(ps.price_sold)
from productsales ps
join
(
select 1 as grpid, 1 as product_id
union all
select 1 as grpid, 2 as product_id
union all
select 2 as grpid, 2 as product_id
union all
select 2 as grpid, 3 as product_id
) pg on ps.product_id = pg.product_id
group by pg.grpid;
SQL Fiddle:
SELECT 'GROUP 1' AS `Group`, SUM(price_sold) AS PriceSum
FROM MyTable
WHERE product_id = 1 OR product_id = 2
UNION
SELECT 'GROUP 2', SUM(price_sold)
FROM MyTable
WHERE product_id = 2 OR product_id = 3
The result looks like:

MySQL: Select Order Only if all its Items are ready status

I will simplify the table like this:
table order:
order_id | name
1 a
2 b
3 c
Table order_item:
item_id | fk_order_id | status
1 1 0
2 1 1
3 2 1
4 2 1
5 3 0
Ready status let say is 1, so only order_id=2 has all its items are on ready status.
How can I query select it?
There are a couple ways of doing this -- here is one using COUNT -- gets COUNT of all and compares to COUNT of Status = 1:
SELECT fk_order_id
FROM (
SELECT fk_order_id,
COUNT(1) totCount,
COUNT(CASE WHEN Status = 1 THEN 1 END) statusCount
FROM Order_Item
GROUP BY fk_order_id
) t
WHERE totCount = statusCount
SQL Fiddle Demo
This could be consolidated into a single query, but I think it reads better using a subquery.
Try this:
SELECT order_id ,name FROM order,order_item
WHERE order.order_id =order_item.fk_order_id
group by order_id ,name having min(status)=1

MySQL: fetching an id from an associative table, with specific associations

I've got the following associative table between packages and products (simplified):
package_id product_id count
1 1 6
1 2 1
1 3 1
2 1 6
2 2 1
3 1 6
4 1 8
4 2 1
I'm trying to work out how to create an query which is able to select specific package_id's which contain exactly the products and their counts I supply. So if I'd be trying to find the package that contains: (product_id = 1 AND count = 6) AND (product_id = 2 AND count = 1), it should only return package_id 2 and not the others, because those contain other products and / or other counts.
I'd be happy to work this out in my code (PHP) instead of SQL, but since I'm trying to get to the bottom of queries, I'd like to know how this is done.
This is called Relational Division
SELECT a.package_ID
FROM tableName a
WHERE (a.product_ID = 1 AND a.count = 6) OR
(a.product_ID = 2 AND a.count = 1)
GROUP BY a.package_ID
HAVING COUNT(*) = 2 AND
COUNT(*) = (SELECT COUNT(*) FROM tableName WHERE package_ID = a.package_ID)
SQLFiddle Demo
OR
SELECT package_ID
FROM tableName
WHERE (product_ID, `count`) in ((1, 6), (2, 1))
GROUP BY package_ID
HAVING COUNT(DISTINCT product_ID, `count`) = 2 AND
COUNT(*) = (SELECT COUNT(*) FROM tableName WHERE package_ID = a.package_ID)
SQLFiddle Demo

MySQL Selecting between ANY and ALL

I have a mysql Table T1 consisting of two columns of INTs that links a car_id to a part_id. A single car_id can have multiple part_ids, and the same part_id can correspond to more than one car_id. For example,
car_id part_id
1 1
1 2
1 8
2 3
3 4
4 2
4 6
...
10 1
10 2
...
20 1
20 2
20 8
To get all the part_ids associated with car_id = 1, I run the query,
SELECT car_id, part_id FROM T1 WHERE car_id=1
and get the result:
car_id part_id
1 1
1 2
1 8
Now, I want to find all the remaining car_ids that contain at least (say >= 2/3) of the part_ids associated with car_id=1. (In this example, I should get all car_ids that have at least 2 of the part_ids 1,2, and 8 as shown after my SELECT query. So, I should get car_ids 1,10, and 20).
I can find the car_ids that contain All of the part_ids 1,2, and 8 using:
SELECT car_id, part_id
FROM T1
WHERE part_id = ALL (SELECT part_id FROM T1 WHERE car_id=1). The result is car_ids 1 and 20.
I can find the car_ids that contain ANY of the values 1,2, and 8 using:
SELECT car_id, part_id
FROM T1
WHERE part_id = ANY (SELECT part_id FROM T1 WHERE car_id=1). The result is car_ids 1,4,10 and 20.
How can I specify some number between ANY and ALL?
To get all car_ids that have 2 or more of car 1's part_ids do
SELECT car_id,
group_concat(part_id) as part_ids
FROM T1
WHERE part_id in (SELECT part_id FROM T1 WHERE car_id = 1)
group by car_id
having count(distinct part_id) >= 2
Here is one way:
select car_id
from (select cp.car_id,
sum(case when cp.part_id is not null and cp1.part_id is not null then 1 else 0 end) as PartsInCommon,
sum(case when cp.part_id is not null and cp1.part_id is null then 1 else 0 end) as ThisCarOnly,
sum(case when cp.part_id is null and cp1.part_id is not null then 1 else 0 end) as ThatCarOnly
from CarParts cp full outer join
(select part_id
from CarParts cp
where car_id = 1
) cp1
on cp.part_id = cp1.part_id
group by cp.car_id
) t
where PartsInCommon / (PartsInCommon + ThisCarOnly + ThatCarOnly) >= 2.0/3
This query counts the number of parts common to both cars or in one or the other. The where clause then defines the particular condition.
If you want the list of parts, then Juergen has the right idea with the group_concat(), although you don't specify this in the question.
Try this query. I have tried as much as i can
SELECT
car_id,
GROUP_CONCAT(part_id)
FROM cars
WHERE FIND_IN_SET
(part_id ,(SELECT GROUP_CONCAT(part_id) FROM cars WHERE car_id = 1))
GROUP BY car_id
HAVING COUNT(part_id) >= 2
Here is the sqlfiddle Demo http://sqlfiddle.com/#!2/8e563/17