How to select unique value from many to many mysql relationship - php

Hi I got confused in this sql case. I am using mysql Ver 15.1 Distrib 10.2.31-MariaDB. And let's say I have 3 table products, categories, and product_categories as pivot table.
Here is the data example:
products:
| id | name |
------------------------
| 1 | asd wef |
| 2 | gggg2222 |
| 3 | pppga 99 |
| 4 | lalala 55 |
And for categories:
| id | level | parent_id | name |
-----------------------------------
| 20 | 1 | | Fashion |
| 22 | 2 | 20 | Top |
| 23 | 3 | 22 | T-Shirt |
| 24 | 3 | 22 | Jacket |
And for the pivot table, product_categories:
| product_id | category_id |
--------------------------------
| 1 | 20 |
| 1 | 22 |
| 1 | 23 |
| 2 | 22 |
| 2 | 20 |
| 3 | 20 |
| 4 | 20 |
So as you can see from pivot table only product_id = 3 & 4 that stop in category level 1. And product_id = 2 only stop in category level 2.
What I would like to achieve here is when I select from categories table. I can count how many product that stopping here. This is example of the data that I want to get.
"categories": [
{
"id": 20,
"total_product": 4
"stopped_product": 2
},
{
"id": 22,
"total_product": 3
"stopped_product": 1
}
]
So far I tried using group by:
SELECT * FROM product_categories WHERE product_id IN (1, 2, 3, 4) GROUP BY product_id HAVING category_id=20
output:
| product_id | category_id |
--------------------------------
| 1 | 20 |
| 3 | 20 |
| 4 | 20 |
Expected Output
| product_id | category_id |
--------------------------------
| 3 | 20 |
| 4 | 20 |

You can use a CTE to generate a list of stop categories for each product and then JOIN that to the categories and product_categories tables to count the total number of products and number of stopped products for each category:
WITH prods AS (
SELECT product_id, MAX(category_id) AS stop_cat
FROM product_categories
GROUP BY product_id
)
SELECT c.id AS category_id,
COUNT(DISTINCT pc.product_id) AS total_product,
SUM(c.id = p.stop_cat) AS stopped_product
FROM categories c
JOIN product_categories pc ON pc.category_id = c.id
JOIN prods p ON p.product_id = pc.product_id
GROUP BY c.id
Output (for your sample data)
category_id total_product stopped_product
20 4 2
22 2 1
23 1 1
Demo on dbfiddle

I guess you want max values only
SELECT product_id,MAX(category_id) as category_id FROM product_categories WHERE product_id IN (1, 2,
3, 4)
GROUP BY product_id
HAVING category_id=20

Here is you can find category-wise product count and ids:
SELECT c.name as categoryName, c.level, COUNT(pc.product_id) as productCount, GROUP_CONCAT(pc.product_id) as productIds
FROM product_categories pc JOIN categories c ON c.id = pc.category_id
WHERE 1
GROUP by c.id

Related

Need a query to find total distance with some condition?

I have two tables in my database, One is category and second is an entry table.
My Category Table is like below:
----------------------------------
| Cat_ID | cat_type | cat_value |
----------------------------------
| 201 | running | 1 |
| 202 | cycling | 4 |
----------------------------------
My Entry Table is like below:
-------------------------------
| user_id | cat_ID | distance |
-------------------------------
| 1 | 201 | 50 |
| 1 | 201 | 50 |
| 1 | 202 | 100 |
| 1 | 202 | 100 |
| 2 | 201 | 10 |
| 2 | 201 | 10 |
-------------------------------
So Now I want to total distance for user ID "1" but here one condition is that for 201 categories the sum of the total will divide by one and for 202 category total distance will divide by 4 as per category table in cat_value.
Means i want total distance like ((50+50)/1 + (100+100)/4)
So, how can i do this?
Use join and sub-query
select
sum(t1.totald/c.cat_value) as total_distance
from
cat c
join
(select
sum(distance) totald, user_id, cat_id
from
entry where user_id=1 --- if you just want for userid=1
group by
user_id, cat_id) t1 on c.Cat_ID = t1.Cat_ID

MySQL pivot to make a row into a colum

I have three tables, products, customers, order
Product:
id | name |
1 | milk |
2 | bread|
3 | Pea |
Customer:
id | name | category
1 | James | retailer
2 | Paul | vendor
3 | Dave | retailer
Order:
id | product_id | customer_id | qty | price
1 | 1 | 2 | 23 | 50
2 | 2 | 2 | 4 | 30
3 | 3 | 2 | 6 | 10
4 | 2 | 1 | 9 | 30
5 | 3 | 1 | 2 | 10
6 | 1 | 3 | 6 | 50
7 | 3 | 3 | 7 | 10
When i do a query to show transactions by customers with category of vendor like
SELECT customer.name, product.name as pname, order.qty, order.price FROM customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "vendor"
i will get something like:
name | pname | qty | price
Paul | milk | 23 | 50
Paul | bread | 4 | 30
Paul | pea | 6 | 10
I want this instead:
name | milk | bread | pea | total
Paul | 23 | 4 | 6 | 90
While that of retailers will look like this:
SELECT customer.name, product.name as pname, order.qty, order.price FROM
customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "retailer"
I will get a table like this:
name | pname | qty | price
James | bread | 9 | 30
James | pea | 2 | 10
Dave | milk | 6 | 50
Dave | pea | 7 | 10
But i want this instead:
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60
Simply use conditional aggregation for pivoting columns. And be sure to use explicit joins instead of the deprecated implicit join as former has been the standard for 25 years in ANSI-92.
SELECT c.name,
SUM(CASE WHEN p.name = 'milk' THEN o.qty ELSE 0 END) as milk,
SUM(CASE WHEN p.name = 'bread' THEN o.qty ELSE 0 END) as bread,
SUM(CASE WHEN p.name = 'pea' THEN o.qty ELSE 0 END) as pea,
SUM(o.price) AS Total
FROM `customer` c
INNER JOIN `order` o
ON c.id = o.customer_id
INNER JOIN `product` p
ON p.id = o.product_id
WHERE c.category = 'vendor' -- same for retailer
GROUP BY c.name
I think that you cannot have this response structure directly from one simple select
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60
because your database is getting one row foreach retailers/customer order.
I know that using a server language like PHP or Java you will can handle the data and retrive like you want.

Sort product data from multiple tables in MySQL

I have two tables. The first:
Products table:
+----+-----------+
| id | name |
+----+-----------+
| 1 | Product 1 |
| 2 | Product 2 |
| 3 | Product 3 |
+----+-----------+
This contains product names and other table contains prices for different product variants:
Products prices table:
+-----+------------+-------------+
| id | product_id | price |
+-----+------------+-------------+
| 5 | 1 | 12.00 |
| 6 | 1 | 32.00 |
| 11 | 1 | 56.00 |
| 14 | 2 | 11 |
| 44 | 3 | 12 |
+-----+------------+-------------+
I need to create a sort on price (lowest and highest)
Yes you can, for this you have to use JOIN and ORDER BY clause.
Ex:
select t1.id, t2.product_id t2.price FROM table1 t1 JOIN table2 t2 ON t1.id = t2.pid ORDER BY t2.price
Mysql join with order by reference guide
You can try this code...
SELECT product_tbl.name, product_tbl.id, product_price.product_id, product_price.price FROM product_tbl, product_price WHERE product_tbl.id=product_price.product_id ORDER BY product_price.price DESC;
Sample Query:
select t1.[id],t1.[name],t2.[price]
from [yourtable1] t1
Join [yourtable2] t2 on
t1.[id]=t2.[product_id]
Order by t2.[price] Asc;

How to select all the sub_category records with its main_category_name and parent_id in a single query in MySQL?

My category table is looking like the following:
------------------------------------
id | name | parent_id |
------------------------------------
1 | Vehicles | 0 |
2 | Car Insurance | 1 |
3 | Van Insurance | 1 |
4 | PhoneRecharge | 0 |
5 | prepaid | 4 |
6 | postpaid | 4 |
The output should look like the following:
---------------------------------------------------------
id | parent_id | main_category_name | sub_category_name|
---------------------------------------------------------
2 | 1 | Vehicles | Car Insurance |
3 | 1 | Vehicles | Van Insurance |
5 | 4 | PhoneRecharge | prepaid |
6 | 4 | PhoneRecharge | postpaid |
To get the above record, I need to minimize my database interaction. So I need to achieve this above data in a single query.
Here you go: http://sqlfiddle.com/#!9/1b1a7a/14
SQL:
SELECT * FROM category t1 INNER JOIN (SELECT * FROM category WHERE parent_id != 0) t2 ON t1.id = t2.parent_id
This should work:
SELECT
c.id AS cat_id,
parent.id AS parent_id,
parent.name AS main_category_name,
c.name AS sub_category_name
FROM
category c JOIN category parent ON c.parent_id = parent.id

Mysql limit the number of returned results based on the unique values from a single column

I have three tables,
Product_to_categories => contains two columns (Category_id, Product_id)
Product => contains a few columns (product_id, name, sku, ...)
categories => contains a few columns (category_id, name, ....)
I would like to get a result set for the first 10 unique category_id's joined with the product table, a category can have many product assigned to it, i want all products within one category returned, but i'd like to only get the products from the first 8 categories...
Current query:
SELECT p2c.category_id, p.pname, c.category_name
FROM product p LEFT JOIN product_to_category p2c
ON (p.product_id = p2c.product_id)
Left Join category c (p2c.category_id = c.category) LIMIT 0,8
Current output
catID | p.name | catName |<br/>
1 | docs | shoe<br/>
1 | bob | shoe<br/>
1 | mom | shoe<br/>
1 | cat | shoe<br/>
1 | dang | shoe<br/>
1 | kit | shoe<br/>
2 | pis | book<br/>
2 | jiz | book<br/>
Currently i only get the first 8 results regardsless, however i am looking to get the following output:
catID | p.name | catName |<br/>
1 | docs | shoe<br/>
1 | bob | shoe<br/>
1 | mom | shoe<br/>
1 | cat | shoe<br/>
1 | dang | shoe<br/>
1 | kit | shoe<br/>
2 | pis | book<br/>
2 | jiz | book<br/>
3 | docs | shirt<br/>
3 | bob | shirt<br/>
3 | mom | shirt<br/>
4 | cat | light<br/>
4 | dang | light<br/>
5 | kit | sound<br/>
6 | pis | mic<br/>
6 | jiz | mic<br/>
7 | docs | pen<br/>
7 | bob | pen<br/>
7 | mom | pen<br/>
7 | cat | pen<br/>
8 | dang | lace<br/>
8 | kit | lace<br/>
8 | pis | lace<br/>
8 | jiz | lace<br/>
i would like the resultset to contain results of all products that are assigned to the first 8 categories...
Please advise.
Thanks
Hadi
I'm a bit unsure why your query is starting from the product table, so I'm not going to - but aside from this, I think what you need is:
SELECT c.category_id, p.pname, c.category_name
FROM category c
INNER JOIN product_to_category pc ON c.category_id = pc.category_id
INNER JOIN product p ON pc.product_id = p.product_id
WHERE c.category_id in (SELECT TOP 8 category_id FROM Category)
ORDER BY 1, 2

Categories