How to join with table that have no record? - mysql

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'

Related

Get records from one table and a corresponding table

I have two tables:
orders
poid | user | pid | payment_id
1 | 1 | 1 | abc123
2 | 2 | 2 | def345
orders_addon
poaid | user | poid | pid
1 | 1 | 1 | 3
2 | 1 | 1 | 5
One represents orders, the second one represent addons a user can add to his order.
There is always a row in orders and it can occur that there is no matching orders_addon for an order.
I'm looking for a query that returns matching rows from orders and orders_addon if there are matching ones.
SELECT user,pid FROM ... WHERE payment_id = 'abc123'
Should return
user | pid
1 | 1
1 | 3
1 | 5
And the same query should only return results from the orders table if there is no matching record in the orders_addon table.
SELECT user,pid FROM ... WHERE payment_id = 'def345'
user | pid
2 | 2
I reckon this could be done using UNION but then I wouldn't be able to match the tables and it would become a problem since the orders_addon table doesn't have a payment_id
Use LEFT JOIN WITH IF STATMENT
mysql> ( SELECT u.user,IFNULL(ua.pid ,u.pid) as pid
FROM orders u
inner JOIN orders_addon ua on ua.poid=u.poid
WHERE u.payment_id = 'abc123'
)
union all
( SELECT u.user,u.pid
from orders u
where u.payment_id = 'def345'
);
+------+------+
| user | pid |
+------+------+
| 1 | 3 |
| 1 | 5 |
| 2 | 2 |
+------+------+
3 rows in set (0.00 sec)
mysql> ( SELECT u.user,IFNULL(ua.pid ,u.pid) as pid
FROM orders u
inner JOIN orders_addon ua on ua.poid=u.poid
WHERE u.payment_id = 'def345'
)
union all
( SELECT u.user,u.pid
from orders u
where u.payment_id = 'def345'
);
+------+------+
| user | pid |
+------+------+
| 2 | 2 |
+------+------+
1 row in set (0.00 sec)

MYSQL - Find records from one table which don't exist in another

I've got the following two SQL tables (in MySQL):
Users
| id | name |
|----|------|
| 1 | Luke |
| 2 | Mark |
| 3 | Lucy |
| 4 | Biff |
User category
| user_id | category_id |
|---------|-------------|
| 1 | 5 |
| 1 | 6 |
| 2 | 5 |
| 2 | 7 |
| 3 | 5 |
I want users that are in User category but not if category id is 6.
In this case Mark and Lucy because Luke is in category 6 too and Biff has no category.
There is a way to do it without subquery and only in one query?
You can group by user_id and eliminate those rows where there is atleast one category_id of 6.
select uc.user_id,u.name
from user_category uc
join users u on uc.user_id = u.id
group by uc.user_id,u.name
having sum(case when category_id = 6 then 1 else 0 end) = 0
Join them and check for difference :
SELECT * FROM users
INNER JOIN user_category ON (user_category.user_id = users.id)
WHERE user_category.category_id <> 6
p.s. using group by is not effective, cuz it says to DB engine to do additional group by operation after gathering data.

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;

Select row from one table where multiple rows in another table have determined values

I have two tables in MySQL:
Products:
id | value
================
1 | foo
2 | bar
3 | foobar
4 | barbar
And properties:
product_id | property_id
=============================
1 | 10
1 | 11
2 | 15
2 | 16
3 | 10
3 | 11
4 | 10
4 | 16
I want to get products that have determined properties.
For example I need to get all products that have properties with ids 10 and 11. And I expect products with ids 1 and 3 but not 4!
Is it possible in mysql or I need to use PHP for it?
Thank you!
with ids 10 and 11
Here's 2 solutions:
SELECT p.id,
p.value,
Count(DISTINCT propety_id)
FROM products p
INNER JOIN properties pr
ON p.id = pr.product_id
AND propety_id IN ( 10, 11 )
HAVING Count(DISTINCT propety_id) = 2;
or....
SELECT p.id,
p.value
FROM products p
INNER JOIN properties pr1
ON p.id = pr2.product_id
AND pr1.propety_id = 10
INNER JOIN properties pr2
ON p.id = pr2.product_id
AND pr2.propety_id = 11;
As for excluding rows - add a NOT exists clause, or do an additional left join and exclude matching rows.
SELECT *
FROM [products]
WHERE id IN (SELECT product_id
FROM [properties]
WHERE propety_id IN ( '10', '11' )
HAVING Count(DISTINCT propety_id) = 2);
Try this:
SELECT p.id
FROM product p
INNER JOIN properties prop
ON p.id = prop.product_id
AND property_id IN ( 10, 11 )
GROUP BY p.id
HAVING Count(DISTINCT property_id) = 2
Here is how I solved it:
mysql> SELECT * FROM products;
+----+--------+
| id | value |
+----+--------+
| 1 | foo |
| 2 | bar |
| 3 | foobar |
| 4 | barbar |
+----+--------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM properties;
+------------+-------------+
| product_id | property_id |
+------------+-------------+
| 1 | 10 |
| 1 | 11 |
| 2 | 15 |
| 2 | 16 |
| 3 | 10 |
| 3 | 11 |
| 4 | 10 |
| 4 | 16 |
+------------+-------------+
8 rows in set (0.00 sec)
Now we select all the product ids, that have property_ids IN (10, 11) and having 2 distinct rows for property_id:
mysql> SELECT
product_id FROM properties
WHERE
properties.property_id IN (10, 11)
GROUP BY
product_id
HAVING
COUNT(DISTINCT property_id) = 2;
+------------+
| product_id |
+------------+
| 1 |
| 3 |
+------------+
2 rows in set (0.01 sec)
Combining this query with SELECT-ing from products:
mysql> SELECT
id, value
FROM
products
WHERE
products.id IN(
SELECT
product_id FROM properties
WHERE
properties.property_id IN (10, 11)
GROUP BY
product_id
HAVING
COUNT(DISTINCT property_id) = 2);
+----+--------+
| id | value |
+----+--------+
| 1 | foo |
| 3 | foobar |
+----+--------+
2 rows in set (0.00 sec)
sql fiddle
Try this one
SELECT Prd.*
FROM products As Prd
LEFT JOIN (SELECT product_id ,SUM(RStatus) As Tt
FROM (SELECT product_id,
CASE
WHEN propety_id = 10 THEN NULL
WHEN propety_id = 11 THEN NULL
ELSE 0
END As RStatus
FROM properties
) A
GROUP BY product_id
) AS Prt ON(Prd.ID = Prt.product_id )
WHERE Prt.Tt IS NULL

Joining two MySQL tables, but with additional conditions?

I have two tables:
Products:
+-------------------------------------------------+
| id | name | category | price |
+-------------------------------------- ----------+
| 1 | item1 | 1 | 0.99 |
| 2 | item2 | 2 | 1.99 |
| 3 | item3 | 3 | 2.95 |
| 4 | item4 | 4 | 2.50 |
+-------------------------------------------------+
Images:
+--------------------------------------------------+
| id | file_name | p_id | priority |
+-------------------------------------- -----------+
| 1 | image1 | 1 | 0 |
| 2 | image2 | 1 | 1 |
| 3 | image3 | 2 | 2 |
| 4 | image4 | 3 | 2 |
| 5 | image5 | 3 | 3 |
| 11 | image6 | 3 | 5 |
| 16 | image7 | 4 | 1 |
| 19 | image8 | 4 | 7 |
+--------------------------------------------------+
I need to get all of product information, as well as the file name of an image for the product. Notice that a product can have more than one image; I want the one with the lowest priority. Also, I only want results for products that are in a certain category.
So, say I need information for products in categories {1,2,3}, then after the query runs the result should return:
+-----------------------------------------------------------------+
| id | name | category | price | file_name |
+-------------------------------------- ----------+---------------+
| 1 | item1 | 1 | 0.99 | image1 |
| 2 | item2 | 2 | 1.99 | image3 |
| 3 | item3 | 3 | 2.95 | image4 |
+-------------------------------------------------+---------------+
I have tried writing a couple of different join statements, but none of them work; not surprising, since I'm a total novice when it comes to SQL.
Any help would be greatly appreciated!
I will add a step by step tutorial, first getting the join right,
then adding some conditions to filter the category and finally, grouping
and using the having clause with a sub-select. You will need to use the last select
in your code. I also tested this on a mysql instance and it works.
I'm using group by in case you need some other complex stuff. It's good to have an example.
The syntax is ansii sql, it should work on all databases not just mysql
-- get everything by joining
select p.*, i.file_name
from products p
join image i on (p.id = i.p_id)
/* get everything by joining
* + filter by category
*/
select p.*, i.file_name
from products p
join image i on (p.id = i.p_id)
where p.category in (1,2,3)
/* get everything by joining
* + filter by category
* + image is the one with the lowest priority
* note: selecting the priority is not necessary
* but it's good for demonstration purposes
*/
select p.*, i.file_name, i.priority
from products p
join image i on (p.id = i.p_id)
where p.category in (1,2,3)
group by p.id
having i.priority = (select min(priority) from image where p_id = p.id)
This is the answer:
select a.id, a.name, a.category, a.price, b.filename as file_name
from products a left join (
select i.p_id, i.filename from (select id, min(priority) as min_p
from images group by p_id) q
left join images i on q.id = i.id
) b on a.id = b.p_id
where a.category in (1, 2, 3);
EXPLANATION:
First, you need to get a set where for each products with lowest priority, which is from this query:
select id, min(priority) as min_p from images group by p_id;
The result will be:
+----+----------+
| id | lowest_p |
+----+----------+
| 1 | 0 |
| 2 | 2 |
| 3 | 2 |
| 4 | 1 |
+----+----------+
4 rows in set (0.00 sec)
The next step will be to get an outer join, in this case I'd choose (arbitrarily according to my preference), the left join:
select i.p_id, i.filename from (select id, min(priority) as min_p
from images group by p_id) q left join images i on q.id = i.id;
This query produce what you want in short:
+------+----------+
| p_id | filename |
+------+----------+
| 1 | image1 |
| 2 | image3 |
| 3 | image4 |
| 4 | image7 |
+------+----------+
4 rows in set (0.00 sec)
Now you just need to decorate this, again using left join:
select a.id, a.name, a.category, a.price, b.filename as file_name
from products a left join (
select i.p_id, i.filename from (select id, min(priority) as min_p
from images group by p_id) q
left join images i on q.id = i.id
) b on a.id = b.p_id
where a.category in (1, 2, 3);
And you'll get what you want:
+------+-------+----------+-------+-----------+
| id | name | category | price | file_name |
+------+-------+----------+-------+-----------+
| 1 | item1 | 1 | 0.99 | image1 |
| 2 | item2 | 2 | 1.99 | image3 |
| 3 | item3 | 3 | 2.95 | image4 |
+------+-------+----------+-------+-----------+
3 rows in set (0.00 sec)
You can also put the products in the right hand side of the left join, depending on what you expected when there is product without images available. The query above will display the view as above, with the file_name field as "null".
On the other hand, it will not display any if you put products on the right hand side of hte left join.
Building on sarwar026's answer...
SELECT p.id, name, priority, price, file_name
FROM Products p, Images i
WHERE p.id = i.p_id
AND i.priority = (SELECT MIN(priority) FROM Images ii WHERE ii.p_id = p.id)
AND p.category IN (1,2,3)
(tested on a mysql database with copies of your tables)