Need a query to find total distance with some condition? - php

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

Related

How to select unique value from many to many mysql relationship

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

MYSQL OR SQL SELECT with both COMPARE (HAVING) and GROUP

I have three tables in a database and want to sum and compare in one SELECT statement.
The logic is that if one article runs low in stock it should be selected. An article runs low if the summarized quantity of all rows with the same artID in the table Articles in stock (an article can have several rows in the table and therefore needs to be summarized) is lower or equal to the column warning in the row with the corresponding ID. This is also warehouse specific, meaning that an article can be fully stocked in one warehouse, and at the same time running low in another. Which is why it is needed to summarize grouped on a specific warehouse.
Information about which warehouse is running low, and such as artNr for the article is also needed, which can be found in table Articles
Articles
+----+-------+---------+
| ID | artNr | warning |
+----+-------+---------+
| 1 | LA08 | 5 |
| 2 | LA09 | 10 |
| 3 | LA58 | 0 |
+----+-------+---------+
warehouse
+----+-------+
| ID | artID |
+----+-------+
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
+----+-------+
Articles in stock
+----+-------+-------------+----------+
| ID | artID | warehouseID | quantity |
+----+-------+-------------+----------+
| 1 | 1 | 3 | 10 |
| 2 | 1 | 5 | 15 |
| 3 | 2 | 5 | 45 |
| 4 | 1 | 3 | 20 |
| 5 | 3 | 5 | 4 |
+----+-------+-------------+----------+
select a.id, s.warehouseID, sum(s.quantity)
from articles a
join articles_in_stock s on a.id = s.artID
group by a.id, s.warehouseID
having sum(s.quantity) <= a.warning

sum the quantity from 3rd relational table

I have following tables, i want to fetch the purchase_order and his order_quantity and sum of received quantity for each purchase_order. i know how to sum the quantity from single table but from multiple tables, it is confusing me a lot...
mysql> select * from purchase_order;
+-------------------+-------------------------+-------+---------------------+
| purchase_order_id | purchase_order | cost | created_on |
+-------------------+-------------------------+-------+---------------------+
| 1 | Dell Computer 000001256 | 10000 | 2015-02-19 22:14:52 |
| 2 | HP Computer 000001256 | 50000 | 2015-02-19 22:14:52 |
+-------------------+-------------------------+-------+---------------------+
2 rows in set (0.00 sec)
mysql> select * from purchase_order_detail;
+--------------------------+-------------------+---------+------------------+
| purchase_order_detail_id | purchase_order_id | item_id | ordered_quantity |
+--------------------------+-------------------+---------+------------------+
| 1 | 1 | 279 | 100 |
| 2 | 1 | 286 | 100 |
| 3 | 2 | 279 | 200 |
| 4 | 2 | 286 | 300 |
+--------------------------+-------------------+---------+------------------+
4 rows in set (0.00 sec)
mysql> select * from delivery_order;
+-------------------+--------------------------+-------------------+---------------------+
| delivery_order_id | purchase_order_detail_id | recieved_quantity | recieved_on |
+-------------------+--------------------------+-------------------+---------------------+
| 1 | 1 | 50 | 2015-02-19 22:22:51 |
| 2 | 2 | 50 | 2015-02-19 22:24:59 |
| 3 | 1 | 50 | 2015-02-19 22:34:14 |
| 4 | 3 | 70 | 2015-02-20 11:11:31 |
| 5 | 4 | 150 | 2015-02-20 11:11:31 |
| 6 | 3 | 90 | 2015-02-20 11:12:20 |
| 7 | 4 | 100 | 2015-02-20 11:12:20 |
| 8 | 3 | 40 | 2015-02-20 11:12:55 |
| 9 | 4 | 50 | 2015-02-20 11:12:55 |
+-------------------+--------------------------+-------------------+---------------------+
So far, i have this query, but id doesn't returns correct record..
SELECT po.purchase_order_id, SUM(pod.ordered_quantity) AS Sum_of_ordered_quantity, SUM(dor.recieved_quantity) AS Sum_of_recieved_quantity
FROM purchase_order AS po
INNER JOIN purchase_order_detail AS pod ON po.purchase_order_id = pod.purchase_order_id
INNER JOIN delivery_order AS dor ON dor.purchase_order_detail_id = pod.purchase_order_detail_id
GROUP BY po.purchase_order_id
it returns this,
+-------------------+-------------------------+--------------------------+
| purchase_order_id | Sum_of_ordered_quantity | Sum_of_received_quantity |
+-------------------+-------------------------+--------------------------+
| 1 | 300 | 150 |
| 2 | 1500 | 500 |
+-------------------+-------------------------+--------------------------+
you can see in the question that , purchase_order_id 1 has 200 ordered quantity and 150 received quantity while purchase_order_id 2 has 500 ordered_quantity and 500 received quantity.
Please try this code:
SELECT po.purchase_order_id,
SUM(pod.ordered_quantity) AS Sum_of_ordered_quantity,
(SELECT `mySelect`.`desired_sum` FROM
(SELECT B.`purchase_order_id` AS myID, SUM( `A`.`recieved_quantity` ) AS desired_sum
FROM `delivery_order` AS A
LEFT JOIN `purchase_order_detail` AS B ON A.purchase_order_detail_id = B.purchase_order_detail_id
GROUP BY B.`purchase_order_id` ) AS mySelect
WHERE `mySelect`.`myID` = `po`.`purchase_order_id`) AS Sum_of_received_quantity
FROM purchase_order AS po
INNER JOIN purchase_order_detail AS pod ON po.purchase_order_id = pod.purchase_order_id
GROUP BY po.purchase_order_id
This is usual while doing aggregate sum function with multiple many-to-many tables with different joining condition.
One way is to use correlated subquery to get the aggregate value and then do the join. Something as
select
po.purchase_order_id,
pod.Sum_of_ordered_quantity,
do.Sum_of_received_quantity
from purchase_order po
join
(
select purchase_order_id,sum(ordered_quantity) as Sum_of_ordered_quantity
from purchase_order_detail
group by purchase_order_id
)pod on pod.purchase_order_id = po.purchase_order_id
join
(
select
t1.purchase_order_id,
sum(t2.recieved_quantity) as Sum_of_received_quantity
from purchase_order_detail t1
join delivery_order t2 on t1.purchase_order_detail_id = t2.purchase_order_detail_id
group by t1.purchase_order_id
)do on do.purchase_order_id = po.purchase_order_id
DEMO

Selecting random triplicates (or more) from database

I have two tables:
Students Student_Grades
V------------------------V
+----+------+ +----+------------+---------+-------+
| id | name | | id | student_id | subject | grade |
+----+------+ +----+------------+---------+-------+
| 0 | Dave | | 0 | 0 | Math | 100 |
+----+------+ +----+------------+---------+-------+
| 1 | John | | 1 | 0 | Chem | 90 |
+----+------+ +----+------------+---------+-------+
| 2 | Kate | | 2 | 0 | CompSCI | 95 |
+----+------+ +----+------------+---------+-------+
| 3 | Mimi | | 3 | 1 | ELA | 98 |
+----+------+ +----+------------+---------+-------+
| 4 | 2 | Biology | 92 |
+----+------------+---------+-------+
| 5 | 2 | Chem | 94 |
+----+------------+---------+-------+
| 6 | 2 | Math | 98 |
+----+------------+---------+-------+
| 7 | 3 | Math | 100 |
+----+------------+---------+-------+
I would like to select all subjects and grades from a random student that is enrolled in more than three subjects. (Either Dave or Kate)
Students John and Mimi would not be even considered because they are not enrolled in three subjects.
I know I can achieve this with PHP but I would like this to be done with one query to the database.
SELECT * FROM Students t JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Students) AS x ON t.ID >= x.ID LIMIT 1
With the above query, I have selected a random student, with that I can go in and check if they have three subjects with SELECT count(subjects) FROM Students WHERE id=random_id.
If the count returned is below three, then I throw away the results and run the first query again.
How would I attempt this in one query?
This is tested and working:
SELECT *
FROM Students s
JOIN (
SELECT student_id
FROM Student_Grades
GROUP BY student_id
HAVING COUNT(*) >= 3
ORDER BY RAND()
LIMIT 1
) rs
ON rs.student_id = s.id
JOIN
Student_Grades sg
ON sg.student_id = s.id
Here's the SQL Fiddle: http://sqlfiddle.com/#!2/e5b5b/1

Count the frequency of votes in MySQL

I am making a website where users can vote on which category a page is. They can vote that the page is in category a, b, c, or d.
I need to find the most commonly occurring category in the MySQL row out of all the votes.
Each time a user submits their vote, it submits the "category" that they voted for, and the "page_id".
I have this so far:
SELECT page_id, category
FROM categories
GROUP BY page_id
I cannot use a COUNT(*) WHERE category = 'a' then repeat it for each category because there is many more categories in the actual project.
If your table looks something like this:
SELECT * from categories;
+---------+----------+
| page_id | category |
+---------+----------+
| 1 | a |
| 1 | b |
| 1 | a |
| 1 | c |
| 1 | a |
| 1 | b |
| 1 | a |
| 2 | d |
| 2 | d |
| 2 | c |
| 2 | d |
| 3 | a |
| 3 | b |
| 3 | c |
| 4 | c |
| 4 | d |
| 4 | c |
+---------+----------+
17 rows in set (0.00 sec)
Then you may want to try this query:
SELECT c1.page_id, MAX(freq.total),
(
SELECT c2.category
FROM categories c2
WHERE c2.page_id = c1.page_id
GROUP BY c2.category
HAVING COUNT(*) = MAX(freq.total)
LIMIT 1
) AS category
FROM categories c1
JOIN (
SELECT page_id, category, count(*) total
FROM categories
GROUP BY page_id, category
) freq ON (freq.page_id = c1.page_id)
GROUP BY c1.page_id;
Which returns this:
+---------+-----------------+----------+
| page_id | MAX(freq.total) | category |
+---------+-----------------+----------+
| 1 | 4 | a |
| 2 | 3 | d |
| 3 | 1 | a |
| 4 | 2 | c |
+---------+-----------------+----------+
4 rows in set (0.00 sec)
Compare the results with the actual frequency distribution:
SELECT page_id, category, COUNT(*) FROM categories GROUP BY page_id, category;
+---------+----------+----------+
| page_id | category | COUNT(*) |
+---------+----------+----------+
| 1 | a | 4 |
| 1 | b | 2 |
| 1 | c | 1 |
| 2 | c | 1 |
| 2 | d | 3 |
| 3 | a | 1 |
| 3 | b | 1 |
| 3 | c | 1 |
| 4 | c | 2 |
| 4 | d | 1 |
+---------+----------+----------+
10 rows in set (0.00 sec)
Note that for page_id = 3, there is no leading frequency, in which case this query makes no guarantee on which category will be chosen in such a case.
something like
SELECT category, page_id, count(vote_id)
FROM categories
WHERE category in ('a', 'b', 'c', 'd')
GROUP BY category, page_id
ORDER BY count(vote_id) DESC
LIMIT 1
should do the trick. I assume here the votes are individually stored in a separate row per vote.
It only looks in the cqtegory you're interested in, sorts with the most votes first and only returns the first one.

Categories