find records grouped by two columns in mysql - mysql

I want to find out all seller who have uploaded products in categories (electronics,clothing,furniture), so for 3 categories there can be 3 row against each seller . tables I have are
1.category{category_id,name},
2.seller {seller_id,username},
3.products{product_id,seller_id,category_id,title}
Note:There can be maximum 3 result (coz I'm searching in 3 categories) against one seller even if he added more than one product in single category
expected result:
**product_id** **category** **sellerUsername**
101 electronics kuldeep
211 furniture kuldeep
322 clothing kuldeep
167 electronics roman
245 furniture roman
247 clothing dangi
246 furniture dangi
..
..

if you need only the matching relation use inner join
select a.product_id, b.username, c.name
from products as a
inner join seller as b on b.seller_id = a.seller_id
inner join category as c on c.category_id = a.category_id
else use left join
select a.product_id, b.username, c.name
from products as a
left join seller as b on b.seller_id = a.seller_id
left join category as c on c.category_id = a.category_id

The general solution to your problem is to join the three tables together and then aggregate by seller and category. In my solution, I have arbitraily chosen the max product ID, in the absence of any logic for doing otherwise. The query is slightly tricky, in that we need to additionally join this result again to the category and seller tables to get the human readable category and seller names. The reason for this is the GROUP BY query should ideally be done by ID and not name, since conceivably two categories (or sellers) could have the same name but have different IDs.
SELECT t3.product_id,
COALESCE(t1.name, 'NA'),
COALESCE(t2.username, 'NA')
FROM
(
SELECT MAX(p.product_id) AS product_id,
c.category_id,
s.seller_id
FROM products p
LEFT JOIN category c
ON p.category_id = c.category_id
LEFT JOIN seller s
ON p.seller_id = s.seller_id
WHERE c.name IN ('electronics', 'clothing', 'furniture')
GROUP BY s.seller_id,
c.category_id
) t1
LEFT JOIN category t2
ON t1.category_id = t2.category_id
LEFT JOIN seller t3
ON t1.seller_id = t3.seller_id

Check Below Code.
SET #row_number:=0;
SET #db_names:= '';
SET #db_names2:= '';
select product_id,name as category ,username as sellerUsername
from (
select a.product_id, c.name ,b.username,
#row_number:=CASE WHEN #db_names=username and #db_names2=name THEN #row_number+1
ELSE 1 END AS row_number,#db_names:=username AS username2,#db_names2:=name AS name2
from products as a
left join seller as b on b.seller_id = a.seller_id
left join category as c on c.category_id = a.category_id
where name IN ('electronics', 'clothing', 'furniture')
)a where row_number < 2
order by sellerUsername,name;
Output :

Related

SQL query which return counted results from many tables

I have two tables 'shops' and 'products'. Shop has many products and product belongs to one shop. Moreover product belongs to the only one category. I have id's of 3 categories (for example 1,2,3). How can I get all shops having products which belongs to all 3 categories?
I tried
SELECT distinct s.*
from shops s
left join products p on p.shop_id = s.id
where p.category_id in (1,2,3)
but this returns shops with products which belongs to the category 1 OR 2 OR 3 But I want the products which belongs to the all 3 categories like 1 AND 2 AND 3, so every shop have to have at least 3 products
You could check the s.id having count(distinct p.category_id) = 3
SELECT s.id
from shops s
inner join products p on p.shop_id = s.id
where p.category_id in (1,2,3)
group by s.id
having count(distinct p.category_id) = 3
SELECT s.*
from shops s
join products p
on p.shop_id = s.id
where p.category_id in (1,2,3)
Group
by s.id
Having count(distinct p.category_id) = 3
Or something like that
Try this?
SELECT DISTINCT A.ID FROM SHOPS A, PRODUCTS B
WHERE A.ID = B.SHOP_ID AND EXISTS (SELECT COUNT(1) FROM PRODUCTS C, PRODUCTS D, PRODUCTS E WHERE B.ID = C.ID AND C.ID = D.ID AND D.ID = E.ID AND C.CATEGORY_ID = 1 AND D.CATEGORY_ID = 2 AND E.CATEGORY_ID = 3)
My T-SQL is rusty and this assumes I got the relations correct such that Shops 1 - M Products and, I'm unsure if Category is an entity but Category 1 - M Product. Also, just for future work, I've found it helps when your entities are names singular nouns but that's just my preference. Good luck.
Use group by will return by each shop
SELECT distinct s.*
from shops s
left join products p on p.shop_id = s.id
where p.category_id in (1,2,3)
group by s.id
having count(distinct p.category_id) = 3

Get categories which do not have any product from a particular category

I am trying to write a sql query to get the categories which does not have any of the products from particular category. Let say I have a,b,c,d,e categories and each category have some products. Now I need to get all the categories which done not include products of category a.
Categories table:
id name
1 A
2 B
3 C
4 D
5 E
category_products table:
product_id category_id
1 1
1 2
2 3
2 1
4 3
3 2
3 4
3 5
4 5
Query I used is below which gives B,C,D,E (not as expected)
SELECT DISTINCT c.name FROM category_products AS p
LEFT JOIN categories AS c ON c.id = p.category_id
WHERE p.product_id NOT IN (SELECT DISTINCT product_id FROM category_products where category_id = 1)
ORDER BY c.name
But I need results to be categories D,E which don't have any products from category A.
You need to do one more inner query, e.g.:
SELECT name
FROM categories
where id NOT IN (
SELECT DISTINCT category_id
FROM category_products WHERE
product_id IN (
SELECT product_id FROM category_products WHERE category_id = 1
)
);
This would return D and E.
Here's the SQL Fiddle.
You should use inner join
select distinct t2.name
from category_products t1
inner join Categories t2 on t2.id = t1.category_id
where t1.product_id not in
(select p.product_id
from category_products p
inner join Categories c on c.id = p.category_id
where c.name ='A')
I would be inclined to do this using group by and having:
select pc.product_id
from category_products pc join
categories c
on c.id = pc.category_id
group by pc.product_id
having sum(c.name = 'A') = 0;

MySQL One-To-Many SUM of COUNTs

After 2 days of searching and trying similar questions, it's got to the point where I need to ask the question!
I have the following database structure (simplified)..
mt_product | mt_sku | mt_price
========== | ====== | ========
id | brand_id | mpn | id | product_id | retailer_id | sku | id | sku_id | price | date
For instance...
* A can of Coca-Cola is ONE product.
* It can be sold in many different retailers, who will all have a SKU for it.
* This SKU will have a price, which can change day-by-day.
I want to list the total number of prices for the product.
To list this I currently have the following query which nearly works...
SELECT
p.id AS pid, p.title AS p_title, p.cat, p.mpn,
b.id AS bid, b.name AS brand,
(SELECT COUNT(s.id) FROM mt_sku AS s WHERE s.pid = p.id) AS num_sku,
(SELECT COUNT(gbp.id) FROM mt_price AS gbp INNER JOIN mt_sku ON mt_sku.id = gbp.sid ) AS num_price
FROM mt_product AS p
INNER JOIN mt_brand b ON p.bid = b.id
INNER JOIN mt_sku s ON p.id = s.pid
num_sku returns as expected, however when I introduce the second sub query for num_price (and I have revised this many times) I either get...
* no duplications of the pid but the num_price is the total number of prices to SKUs, not the amount of prices for this product_id (as query above) eg1_img
* the correct number of num_price, but instead of totalling up the total num_price, the pid is duplicated in the table (as query below) - therefore as the pid is duplicated, this does not give me the result I want. I added DISTINCT as it helped an earlier version of the query, it now makes no difference. eg2_img
SELECT
DISTINCT(p.id) AS pid, p.title AS p_title, p.cat, p.mpn,
b.id AS bid, b.name AS brand,
(SELECT COUNT(s.id) FROM mt_sku AS s WHERE s.pid = p.id) AS num_sku,
(SELECT COUNT(gbp.id) FROM mt_price AS gbp WHERE s.id = gbp.sid) AS num_price
FROM mt_product AS p
INNER JOIN mt_brand b ON p.bid = b.id
INNER JOIN mt_sku s ON p.id = s.pid
I'm pretty sure the key to this is that
product can have multiple SKUs, of which a SKU has multiple price history.
Any help or ideas of the schema would be superb.
Try this:
SELECT
p.id AS pid, p.title AS p_title, p.cat, p.mpn,
b.id AS bid, b.name AS brand,
COUNT(DISTINCT s.id) AS num_sku,
COUNT(gbp.id) AS num_price
FROM mt_product AS p
INNER JOIN mt_brand b ON p.brand_id = b.id
INNER JOIN mt_sku s ON p.id = s.product_id
INNER JOIN mt_price gbp ON s.id = gbp.sku_id
GROUP BY b.id, p.id
The products that don't have SKUs defined will not appear in the result set. Use LEFT JOIN mt_sku to make them appear in the result set (having 0 for num_sku and num_price):
LEFT JOIN mt_sku s ON p.id = s.product_id
In both variants of the query, the products that do not have prices defined will not appear in the result set. Use LEFT JOIN mt_price to include them into the result set (having 0 for num_price):
LEFT JOIN mt_price gbp ON s.id = gbp.sku_id
Take a look at the MySQL documentation for JOINs, GROUP BY and GROUP BY aggregate functions.
If you want to list the total prices then you need correlations.
Your first count is fine, because it is correlated to the outer query. The second has no correlation, so that seems strange. The following fixes the num_price subquery:
SELECT p.id AS pid, p.title AS p_title, p.cat, p.mpn,
b.id AS bid, b.name AS brand,
(SELECT COUNT(s2.id) FROM mt_sku s2 WHERE s2.pid = p.id) AS num_sku,
(SELECT COUNT(gbp.id) FROM mt_price gbp WHERE s.id = gbp.sid ) AS num_price
FROM mt_product p INNER JOIN
mt_brand b
ON p.bid = b.id INNER JOIN
mt_sku s
ON p.id = s.pid;
I'm also not sure why you have all the joins in the outer query. I assume that a given product is going to have multiple rows, and you want the multiple rows to have the same num_sku and num_price values.

Display productlist with categories wont show not coupled categories

I have 3 tables, products, categories and couple_product_category
I want all the products from the database with a string of coupled categories.
That works fine however, when I add a new product, which is not coupled to a category yet, wont be return.
I want the fastest way to prevent performance.
This is what I have for now:
SELECT
product.id,
product.product_name,
GROUP_CONCAT(productcategory.name SEPARATOR '; ') AS categories
FROM
m_catalog_products AS product
LEFT JOIN
couple_product_category AS category
ON
category.product_id = product.id
INNER JOIN
m_catalog_productcategoy AS productcategory
ON
productcategory.id = category.category_id
GROUP BY
product.id
ORDER BY product.id, product.is_active ASC
This will result in something like:
ID Name Categories
-- --------- ----------------------
1 Product A Category A; Category B
2 Product B Category C
However, if Product C is not coupled to any category yet, it should shows up like:
ID Name Categories
-- --------- ----------------------
1 Product A Category A; Category B
2 Product B Category C
3 Product C
LEFT JOIN m_catalog_productcategoy instead of INNER JOIN:
SELECT
p.id,
p.product_name,
GROUP_CONCAT(pc.name SEPARATOR '; ') AS categories
FROM m_catalog_products AS p
LEFT JOIN couple_product_category AS c ON c.product_id = p.id
LEFT JOIN m_catalog_productcategoy AS pc ON pc.id = c.category_id
GROUP BY p.id
ORDER BY p.id, p.is_active ASC;

Mysql: How to get values from other table base from an id

Assuming that I have 3 tables on my database
Table:Category
category_id
Table:container
container_id
category_id
Table:products
container_id
product_id
How do you get all product_id based on a category_id?
For example I have these data inside my tables from above:
Table: category
sour
sweet
Bitter
Table: container
bottled
sachet
Table: product
sugar
vinegar
cocoa
How do you get all Product(tb_product) where category(tb_category) is sweet
You can use INNER JOIN to solve your problem.
SELECT a.*
FROM products a
INNER JOIN container b
on a.container_id = b.container_ID
INNER JOIN Category c
ON b.category_ID = c.categoryID
WHERE c.categoryName = 'sweete'
As you can see, I assume that the Category table has columns category_ID and categoryName. So in my example above,I've use category name to search for all products that belong on certain category.
select p.*
from Category c
join container c2 on c2.category_id = c.category_id
join product p on p.container_id = c2.container_id
where c.name = 'sweet';
Note the order of the tables in the query (which should perform faster than the other answer!)
you can use inner join like this:
SELECT a.product_id FROM products AS a INNER JOIN container AS b on a.container_id = b.container_Id INNER JOIN Category AS c on b.category_Id = c.category_id where c.category_id = 'new'