SQL - Join multiple tables and count() - mysql

I am trying to count the number of results in a column after joining a table and I am having a hard time getting my query to work.
In the end result, I need to get a table with the product id, product name and the number of medias for each product.
This is what I have so far:
SQL
select
p.id,
p.name,
count(distinct mp.media_id)
from products as p
left join medias_products as mp
on mp.product_id = p.id
group by mp.media_id
order by p.id
These are the tables:
Medias
Id | client id
------ | ---------
1 | 1
2 | 2
Products
id | name | client_id
------ | -------- | ---------
1 | product1 | 1
2 | product2 | 2
medias_products
product_id | media_id
---------- | --------
1 | 2
2 | 1
Client
id | name
------ | -----
1 | Peter
2 | John
In addition, I'd like to find another query that would give me the results filtered by an specific client id.
Can someone please shed some light and share the knowledge.
Thanks in advance.

Try this:
select
p.id,
min(p.name) as name,
count(distinct mp.media_id) as medias
from products as p
left join medias_products as mp
on mp.product_id = p.id
group by p.id
order by p.id
For your second query:
select
p.id,
min(p.name) as name,
count(distinct mp.media_id) as medias
from products as p
inner join medias_products as mp
on mp.product_id = p.id
inner join medias as m
on m.id = mp.media_id
inner join clients as c
on c.id = m.client_id
where c.id = <your client's id>
group by p.id
order by p.id

Shouldn't you GROUP BY p.id instead of mp.media_id? That is
select
p.id,
p.name,
count(distinct mp.media_id)
from
products as p
left join medias_products as mp
on p.id = mp.product_id
group by p.id
order by p.id

Related

MySQL select from two table based on multiple conditions in same table

I'm trying to build a filter to quickly find the right product based on some specifications. But I can't get the MySQL to work. Been gooogling for a while now but can't find a similar question. I hope you can help me.
This is the products table
--------------------
| id | name |
--------------------
| 1 | Product 1 |
| 2 | Product 2 |
| 3 | Product 3 |
--------------------
This is the relation table for the specifications
--------------------------------
| id | specs_id | prod_id |
--------------------------------
| 1 | 1 | 1 |
| 2 | 5 | 1 |
| 3 | 6 | 2 |
| 4 | 9 | 3 |
| 5 | 11 | 2 |
---------------------------------
This is the MySQL how I want it to work.
$sql = "SELECT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id = 1
AND s.specs_id = 5
AND s.specs_id = 7
GROUP BY p.id";
This example will give no result
$sql = "SELECT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id = 1
AND s.specs_id = 5
GROUP BY p.id";
This will return product with ID 1
Item_id does not exist in your table. You also used AND insted of OR, thus no entry could match. None can have the specs_id 2,5, and 7 at the same time.
SELECT p.id, p.name
FROM products p
JOIN specs s
ON p.id = s.prod_id
WHERE s.specs_id = 5
OR s.specs_id = 2
OR s.specs_id = 7
GROUP BY p.id;
Maybe OR or IN is what you are looking for:
SELECT DISTINCT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id IN (1,5);
or
SELECT DISTINCT p.id, p.name
FROM products p
JOIN specs s ON p.id = s.prod_id
WHERE s.specs_id=1 OR s.specs_id=5;
Also, use DISTINCT instead of GROUP BY if you do not have aggregate functions.
You can do like first filter specs table with required specs_id and then make join that result with products table.
select p.id, p.name from
(select * from products p ) p
join (select * from specs where specs_id in (1,5,7)) s
on p.id = s.prod_id
group by p.id

SQL Filter products from one table basing on attributes from second one

So I have table with products
id | product_name
1 | Product 1
2 | Product 2
3 | Product 3
... table with atributtes:
id | attribute
1 | big
2 | orange
3 | expensive
and table with products and their attributes
id | product_id | attribute_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 3
4 | 3 | 2
and what I want is to filter big, orange products.. in this case: Product 1
Something like:
SELECT product_name
FROM products as a
JOIN products_attributes as b ON a.id=b.product_id
WHERE b.attribute_id = 1 OR b.attribute_id=2
will not work as it returns Product 3 as well..
This doesn't work too, of course:
SELECT product_name
FROM products as a
JOIN products_attributes as b ON a.id=b.product_id
WHERE b.attribute_id = 1 AND b.attribute_id=2
Please help :)
You need to add atributtes table into your SELECT statement and
filter by attribute IN ( 'big','orange' )
GROUPing with HAVING clause should be added to satisfy the both conditions at the same time
SELECT p.product_name
FROM products as p
JOIN products_attributes as pa
ON p.id = pa.product_id
JOIN attributes a
ON a.id = pa.attribute_id
WHERE a.attribute IN ( 'big','orange' )
GROUP BY p.product_name
HAVING COUNT(DISTINCT a.attribute) = 2
using IN rather than OR operator is more straightforward to use .
Demo
In order to find products that have multiple attributes, first we need to join the attributes table with itself:
SELECT pa1.product_id FROM products_attributes as pa1
JOIN products_attributes as pa2 ON pa1.product_id = pa2.product_id
AND pa1.attribute_id = 1 AND pa2.attribute_id = 2
This will output 1, which is the correct id. Note that it doesn't matter which of the two tables you will select the product_id from, since you're joining it with itself and both will contain it.
Now all we need is the name, so we're going to join the products table as well and change our selection:
SELECT p.product_name FROM products p
JOIN products_attributes as pa1 ON pa1.product_id = p.id
JOIN products_attributes as pa2 ON pa1.product_id = pa2.product_id
AND pa1.attribute_id = 1 AND pa2.attribute_id = 2
This should output "Product1".

SQL Join Query Select

I have the following Tables :
Table : product
--------------------------
id_product | name_product
--------------------------
1 | p1
2 | p2
3 | p3
Table : number
-----------------------
imei | id_product
-----------------------
56789 | 1
56799 | 2
56713 | 3
Table : Operatio
----------------------
imei | date
------------------
56789 |31-07-2017
At last I want to get this result :
---------------------------------------
name_product | number_operation
---------------------------------------
p1 | 1
p2 | 0
p3 | 0
Thanks You
This will count the number of operations by product:
select name_product, sum(num_op)
from product p1
left join number n2
on n2.id_product = p1.id_product
left join
(
select imei, count(operation) as num_op
from Operation
group by imei
) x
on x.imei = n2.imei
group by name_product
For the number of products that have had an operation:
select name_product, count(distinct o3.imei)
from product p1
left join number n2
on n2.id_product = p1.id_product
left join Operation o3
on o3.imei = n2.imei
group by name_product
A possible solution :
SELECT name_product, COUNT(*)
FROM product p
LEFT JOIN number n ON n.id_product = p.id_product
LEFT JOIN operation o ON o.imei = n.imei
GROUP BY p.id_product
SELECT product.id_product,COUNT(number.id_product)
FROM product
INNER JOIN number ON product.id_product = number.id_product;
GROUP BY product.id_product
SELECT name_product, count (imei) c
FROM (SELECT name_product, o.imei
FROM (SELECT p.name_product, n.imei
FROM product p, "number" n
WHERE p.id_product = n.id_product) t
LEFT JOIN
Operatio o
ON t.imei = o.imei)
GROUP BY name_product
Try this code

How to mysql distinct one of many count fields when GROUP BY doesn't work?

I've a database with products, manufactors and categories of this products and information about name of manufactors, products and if those products have images.
But in this database are duplicated products with different IDs. Only thing I can identify them is their name.
Now I've a query where I want see how many products per manufactorer and per category were in my database and count also the number of products with images.
-----------------------------------------------------
| manufactor | category | products | productsImages |
|------------|----------|----------|----------------|
| manu-1 | cat-1 | 5 | 3 |
|------------|----------|----------|----------------|
| manu-1 | cat-2 | 15 | 8 |
|------------|----------|----------|----------------|
| manu-2 | cat-1 | 11 | 0 |
|------------|----------|----------|----------------|
| manu-3 | cat-2 | 5 | 4 |
|------------|----------|----------|----------------|
| manu-3 | cat-3 | 9 | 4 |
|------------|----------|----------|----------------|
My approach looks like:
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(p.`name`) AS products,
COUNT(pi.`idImage`) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;
I can't group by p.name because then I'd get a result row for each product.
Do COUNT(DISTINCT(p.name)) didn't help either.
So any suggestions or will I have do to subqueries?
If you want to count the distinct names where pi.`idImage` IS NOT NULL you can use the following:
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(DISTINCT p.`name`) AS products,
COUNT(DISTINCT CASE
WHEN pi.`idImage` IS NOT NULL THEN p.`name`
ELSE NULL
END) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;
See comments on question - distinct on p.name is the solution.
SELECT m.`name` AS manufactor,
pg.`name` AS category,
COUNT(DISTINCT(p.`name`)) AS products,
COUNT(pi.`idImage`) AS productsImages
FROM `product` AS p
LEFT JOIN `product_image` AS pi ON pi.`idProduct` = p.`id`
INNER JOIN `manufacturer` AS m ON m.`id` = p.`idManufacturer`
INNER JOIN `product_groupname` AS pg ON pg.`id` = p.`idProductGroup`
GROUP BY p.`idManufacturer`, p.`idProductGroup`
ORDER BY m.`name`, p.`idProductGroup`;

MYSQL - Get rows in all the selected categories

I'm trying to write query to a MYSQL database that queries for products that have a relationship with all selected categories
Products table
product_id | product_name
---------------------------------
1 | product name one
2 | product name two
3 | product three
Category table
category_id | category_name
1 | category one
2 | category two
3 | category three
Category_relationship table
product_id | category_id
--------------------------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 2
3 | 3
So for example:
category ID's 1 and 3 are selected
Only product_id to be returned would be '1'
Using 2 JOINs
SELECT
p.*
FROM products p
JOIN category_relationship r1
ON r1.product_id = p.product_id
JOIN category_relationship r2
ON r2.product_id = p.product_id
WHERE r1.category_id = 1
AND r2.category_id = 3
Using GROUP BY
SELECT
p.*
FROM products p
JOIN category_relationship r
ON r.product_id = p.product_id
WHERE r.category_id IN (1,3)
GROUP BY p.product_id
HAVING COUNT(*) = 2 <-- number of category ids
It depends on your tables size and data distribution but I'd guess the first query to be faster.
But if you have lists of various sizes to check (with 3, 4, ... category ids), the first query has to be built dynamically while the second can be easily adjusted.
Join it twice:
select p.*
from products p
join category_relationship c1 on c1.product_id = p.product_id
and c1.category_id = 1
join category_relationship c2 on c2.product_id = p.product_id
and c2.category_id = 3
Try this:
SELECT DISTINCT product_id FROM category_relationship WHERE category_id IN (1, 3)
For example:
SELECT *
FROM Products P, Category_relationship CP
WHERE P.product_id = CP.product_id
AND CP.category_id IN (1,3)
SELECT p.product_id, p.product_name
FROM products p LEFT JOIN category_relationship cp ON p.product_id = cp.product_id
GROUP BY p.product_id, p.product_name
HAVING COUNT(cp.category_id) = (SELECT COUNT(*) FROM categories)