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;
Related
I have a table tblPhotos of photo details:
| photoID | photoName |
| ------- | --------- |
| 1 | w |
| 2 | x |
| 3 | y |
| 4 | z |
and another table tblPhotoTags of tags to photos:
| photoID | tagID |
| ------- | ----- |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
| 4 | 2 |
I am trying make a couple of queries that will pick out the photos that have any given tags, either AND or OR. In the example let's say I am searching for the photos linked to tagID 1 AND/OR 2.
OR should pick out all of the photos (1, 2, 3 and 4).
AND should only pick out 1 and 4.
I have the following for OR which works fine:
SELECT DISTINCT tblPhotos.photoID FROM tblPhotos
INNER JOIN tblPhotoTags ON tblPhotos.photoID = tblPhotoTags.photoID
WHERE tblPhotoTags.tagID = 1 OR tblPhotoTags.tagID = 2
But I am struggling to work out how to do the AND query.
If you need only the ids of the photos, then there is no need to join to tblPhotos.
For the 1st case (OR), use DISTINCT and just a WHERE clause:
SELECT DISTINCT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2);
For the 2nd case (AND) use aggregation and set the condition in the HAVING clause:
SELECT photoID
FROM tblPhotoTags
WHERE tagID IN (1, 2)
GROUP BY photoID
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
If you also want the name of the photos then join to tblPhotos:
SELECT DISTINCT p.*
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2);
and:
SELECT p.photoID, p.photoName
FROM tblPhotos p INNER JOIN tblPhotoTags t
ON t.photoID = p.photoID
WHERE t.tagID IN (1, 2)
GROUP BY p.photoID, p.photoName
HAVING COUNT(*) = 2 -- the number of tagIDs in the IN list
See the demo.
I have written a query to get the items from the table which doesn't have any child items. It's working fine but is very slow.
Any better/easier/optimized way to write the same thing?
select distinct id, (select count(i.item_id) from order_item as i where i.parent_item_id = o.item_id) as c
from order_item as o
where product_type = 'bundle'
having c = 0
order by id desc
limit 10;
Few of the fields are these to get the idea of a structure
Table: order_item
Columns:
item_id PK
order_id
parent_item_id
product_id
product_type
item_id | order_id | parent_item_id | product_id | product_type
-----------------------------------------------------------------
1 | 1 | null | 1 | bundle
2 | 1 | 1 | 2 | simple
3 | 1 | 1 | 3 | simple
4 | 1 | null | 4 | bundle
5 | 2 | null | 1 | bundle
6 | 2 | 5 | 2 | simple
7 | 2 | 5 | 3 | simple
Query should only return the 4rth item
Try below. Also consider creating indexes on PARENT_ITEM_ID and ITEM_ID
SELECT OI.*
FROM ORDER_ITEM OI
LEFT JOIN ORDER_ITEM OI2
ON OI2.PARENT_ITEM_ID = OI.ITEM_ID
WHERE OI.PRODUCT_TYPE = 'bundle' AND OI2.PARENT_ITEM_ID IS NULL
I would suggest not exists:
select oi.*
from order_item oi
where oi.product_type = 'bundle' and
not exists (select 1
from order_item oi2
where oi2.parent_item_id = oi.item_id and oi2.product_type = 'bundle'
)
order by id desc
limit 10;
For performance, you want an index on order_item(parent_item_id, product_type).
Note: I'm not sure you want the product_type filter in the subquery, but it is the logic your query is using.
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
)
I have this two table products and wishlist. Here is the structure
And here is wishlist
Here is my query
SELECT a.productId,productName,isNew,isHot,productImage,a.categoryId,productPrice,productDescription,
IF(b.UserId = NULL, 1,0) as isLiked
from products a LEFT JOIN wishlist b on (a.productId = b.productId) and (a.categoryId = b.categoryId)
where b.userId = 'usr001'
But the the query is not showing any records, when I delete the condition it showing the records of products.
So I want to showing the records of product even using the condition, how can I fix it?
This works as expected
Products
+----+-----------+
| id | name |
+----+-----------+
| 1 | product 1 |
| 2 | product 2 |
| 3 | product 3 |
| 4 | product 4 |
| 5 | product 5 |
+----+-----------+
5 rows in set (0.00 sec)
create table wishlist
(userid int, productid int,name varchar(20));
insert into wishlist values
(1,1,'product 1'),
(1,3,'product 3');
select p.id,p.name,if(w.productid is null, 0 , 1 ) isliked
from products p
left join wishlist w on w.productid = p.id and p.name = w.name and w.userid = 1
order by p.id limit 5;
+----+-----------+---------+
| id | name | isliked |
+----+-----------+---------+
| 1 | product 1 | 1 |
| 2 | product 2 | 0 |
| 3 | product 3 | 1 |
| 4 | product 4 | 0 |
| 5 | product 5 | 0 |
+----+-----------+---------+
5 rows in set (0.00 sec)
I don't see a difference between my model and yours - It would help if you added sample data as text to the question together with the table defintions(as text).
Use b.userId = 'usr001' in ON Clause instead of where clause
SELECT a.productId,productName,isNew,isHot,productImage,a.categoryId,productPrice,productDescription,
IF(b.UserId is NULL, 1,0) as isLiked
from products a LEFT JOIN wishlist b on (a.productId = b.productId) and (a.categoryId = b.categoryId)
and b.userId = 'usr001'
EDIT: SQL Fiddle here
I'm working on a product feed. I get a list of offers;
Every offer has 1 product
Every product belongs to 1 category
A category can be a subcategory to another category
I have three tables (of which i will only show you the relevant rows)
Offers:
OFFERS
___________________
| id | product_id |
-------------------
| 1 | 16 |
-------------------
| 2 | 54 |
-------------------
| 3 | 52 |
-------------------
| 4 | 20 |
-------------------
| 5 | 7 |
-------------------
| 6 | 5 |
-------------------
Products:
PRODUCTS
_______________
| id | cat_id |
---------------
| 16 | 1 |
---------------
| 54 | 3 |
---------------
| 52 | 4 |
---------------
| 20 | 1 |
---------------
| 7 | 15 |
---------------
| 5 | 3 |
---------------
Categories:
CATEGORIES
_____________________________________________________________
| id | display_name | original_name | subcat_of | is_active |
-------------------------------------------------------------
| 1 | Cars | automobiles | 0 | 1 |
-------------------------------------------------------------
| 2 | | motorcycles | 0 | 0 |
-------------------------------------------------------------
| 3 | Muscle cars | muscle-cars | 1 | 1 |
-------------------------------------------------------------
| 4 | Hybrid cars | treehugwagons | 1 | 1 |
-------------------------------------------------------------
I have to write two queries. The first one needs to
return the names and count the amount of offers for a given main category and its subcategories
but only if that main category is active
and if a category has no display_name, use the original_name
I think i have this one down:
SELECT
offers.id AS offer_id,
product_id,
products.cat_id,
CASE
WHEN categories.display_name <> ''
THEN categories.display_name
ELSE categories.original_name
END AS cat_name,
COUNT(offers.id) as num_offers
FROM
offers
INNER JOIN
products
ON
product_id = products.id
INNER JOIN
categories
ON
cat_id = categories.id
WHERE
categories.is_active = 1
AND
(categories.id = :cat_id OR categories.subcat_of = :cat_id)
GROUP BY
cat_name
ORDER BY
cat_name ASC
I'm pretty sure this query is far from ideal, but for now, it works.
It is the second query I need that gives me problems. That one needs to:
return the names and count the amount of offers for a given main category and its subcategories and return the sum of those counts per main category
but only if that main category is active
and if a category has no display_name, use the original_name
I could use some PHP to do the summing myself, but I'd be surprised if something that easy could not be done in SQL.
I believe it is possible and fairly simple, assuming you don't have sub-sub-categories:
SELECT CASE
WHEN c_main.display_name <> ''
THEN c_main.display_name
ELSE c_main.original_name
END cat_name,
COUNT(o.id) as num_offers
FROM offers o
JOIN products p
ON o.product_id = p.id
JOIN categories c
ON p.cat_id = c.id
AND (c.id = :cat_id OR c.subcat_of = :cat_id)
/* AND c.is_active = 1 /* Include if necessary */
JOIN categories c_main
ON c_main.id = :cat_id
AND c_main.is_active = 1
GROUP BY cat_name
ORDER BY cat_name ASC
Your first query I would write as:
SELECT CASE
WHEN c.display_name <> ''
THEN c.display_name
ELSE c.original_name
END cat_name,
COUNT(o.id) as num_offers
FROM offers o
JOIN products p
ON o.product_id = p.id
JOIN categories c
ON p.cat_id = c.id
AND (c.id = :cat_id OR c.subcat_of = :cat_id)
AND c.is_active = 1
GROUP BY cat_name
ORDER BY cat_name ASC
As an aside:
I would also consider NULLing out display_names that are empty, then you can replace
CASE
WHEN c_main.display_name <> ''
THEN c_main.display_name
ELSE c_main.original_name
END cat_name
With:
COALESCE(c_main.display_name, c_main.original_name) cat_name
It can't be done in MySQL since MySQL doesn't support recursive queries. You have three choices:
Emulate recursive/hierarchical queries with some complex function. (Related)
Switch to SQL Server which supports recursive queries using CTE.
Write a bit of PHP.
It's up to you :)
As a side note i leave here an interesting slide on Models for Hierarchical data with SQL and PHP written by SO user #Bill Karwin which may suit your situation.