Sql sum() columns from different tables - php

Category Table
mysql> SELECT * FROM cats;
+------+------+-----------+
| c_id | p_id | c_name |
+------+------+-----------+
| 1 | 1 | cats 1 |
| 2 | 1 | cats 2 |
| 3 | 1 | cats 3 |
+------+------+-----------+
Meta Table
mysql> SELECT * FROM meta;
+------+------+------+---------+-------------+-------+
| m_id | p_id | c_id | name | description | costs |
+------+------+------+---------+-------------+-------+
| 1 | 1 | 1 | Abhijit | description | 100 |
| 2 | 1 | 1 | Abhijit | description | 200 |
| 3 | 1 | 2 | Abhiji2 | description | 500 |
+------+------+------+---------+-------------+-------+
Transaction Table
mysql> SELECT * FROM transactions;
+------+------+------+---------------------+--------+
| t_id | p_id | m_id | date | amount |
+------+------+------+---------------------+--------+
| 1 | 1 | 1 | 2016-02-16 11:17:06 | 50 |
| 2 | 1 | 1 | 2016-02-16 11:17:06 | 50 |
| 3 | 1 | 2 | 2016-02-16 11:17:06 | 50 |
| 4 | 1 | 2 | 2016-02-16 11:17:06 | 150 |
+------+------+------+---------------------+--------+
I want to sum() for each category costs (from meta table) and amount( from transaction table).
I use:
mysql> SELECT c.*, SUM(t.amount), SUM(m.costs)
FROM cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id
GROUP BY c.c_id;
+------+------+-----------+--------+---------------+--------------+
| c_id | p_id | c_name | add_by | SUM(t.amount) | SUM(m.costs) |
+------+------+-----------+--------+---------------+--------------+
| 1 | 1 | Abhijit | 1 | 100 | 400 |
| 2 | 1 | Abhiji2 | 1 | 200 | 500 |
+------+------+-----------+--------+---------------+--------------+
It's wrong. The Costs of cats id 1 is 300 but here I got 400
I Want Get Return From Query Like This:
+------+------+-----------+--------+---------------+--------------+
| c_id | p_id | c_name | add_by | SUM(t.amount) | SUM(m.costs) |
+------+------+-----------+--------+---------------+--------------+
| 1 | 1 | Abhijit | 1 | 100 | 300 |
| 2 | 1 | Abhiji2 | 1 | 200 | 500 |
+------+------+-----------+--------+---------------+--------------+

I think you had a typo (or error) in one of your JOIN conditions. I think you intended your original query to be this:
SELECT c.*, SUM(t.amount), SUM(m.costs)
FROM cats c
LEFT JOIN meta m ON m.c_id = c.c_id
LEFT JOIN transactions t ON t.m_id = m.c_id
GROUP BY c.c_id;
Note carefully ON t.m_id = m.c_id, which agrees with your expected output. In any case, I reworked your query as follows:
SELECT c.c_id, c.p_id, c.c_name, t2.transactionCosts, t1.metaCosts
FROM cats c
LEFT JOIN
(
SELECT c_id, SUM(costs) AS metaCosts
FROM meta
GROUP BY c_id
) t1
ON c.c_id = t1.c_id
LEFT JOIN
(
SELECT m_id, SUM(amount) AS transactionCosts
FROM transactions
GROUP BY m_id
) t2
ON c.c_id = t2.m_id
WHERE t2.transactionCosts IS NOT NULL OR t1.metaCosts IS NOT NULL;
The first subquery computes the meta total for each c_id, and the second subquery computes the transaction total for each m_id. These results are then both joined together with the cats table to get your final result.
Follow the link below for a running demo:
SQLFiddle

the problem is you select c.* but only group by c_id, in this case you have 2 options. window function or subquery.
via over(partition by):
SELECT c.*,
SUM(t.amount)over(partition by c.c_id) as amount,
SUM(m.costs)over(partition by c.c_id) as cost
FROM con_cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id;
via subquery:
select a.*,b.amount,b.costs from con_cats a
inner join
(SELECT c.c_id, SUM(t.amount) as amount, SUM(m.costs) as costs
FROM con_cats c
LEFT JOIN meta m ON m.c_id=c.c_id
LEFT JOIN transactions t ON t.m_id=m.m_id
GROUP BY c.c_id) b
on a.c_id = b.c_id;

Related

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 count column from multiple tables. Group results by primary id

I have the following 3 MySQL tables:
products
| id | name | comment_count |
|----|-----------|---------------|
| 1 | Product A | 10 |
| 2 | Product B | 20 |
| 3 | Product C | 30 |
products_views
| product_id | pv_count | pv_date |
| -----------|-------|------------|
| 1 | 10 | 2015-01-01 |
| 1 | 10 | 2015-01-02 |
| 1 | 10 | 2015-01-03 |
| 2 | 20 | 2015-01-01 |
| 2 | 20 | 2015-01-02 |
| 2 | 20 | 2015-01-03 |
| 3 | 30 | 2015-01-01 |
| 3 | 30 | 2015-01-02 |
| 3 | 30 | 2015-01-03 |
products_likes
| product_id | pl_count | pl_date |
| -----------|-------|------------|
| 1 | 10 | 2015-01-01 |
| 1 | 10 | 2015-01-02 |
| 1 | 10 | 2015-01-03 |
| 2 | 20 | 2015-01-01 |
| 2 | 20 | 2015-01-02 |
| 2 | 20 | 2015-01-03 |
| 3 | 30 | 2015-01-01 |
| 3 | 30 | 2015-01-02 |
| 3 | 30 | 2015-01-03 |
I want to add together products.comment_count + product_views.count + product_likes.count grouping by products.id, where product_views.pv_date and product_likes.pl_date between 2015-01-01 and 2015-01-03. Ordering by a total.
What I want:
| product_id | total |
| -----------|-------|
| 3 | 210 |
| 2 | 140 |
| 1 | 70 |
Try this query
SELECT
p.product_id,
(p.comment_count + SUM(pv.count) + SUM(pl.count)) AS total
FROM products p
JOIN products_views pv ON( p.product_id = pv.product_id)
JOIN products_likes pl ON( p.product_id = pl.product_id)
WHERE pl.date BETWEEN '2015-01-01' AND '2015-01-03'
AND pv.date BETWEEN '2015-01-01' AND '2015-01-03'
GROUP BY p.product_id
ORDER BY total DESC
SELECT
(products.comment_count+products_views.pv_count+products_likes.pl_count) AS product_count
FROM products
INNER JOIN products_views.product_id=products.id
INNER JOIN products_likes.product_id=products.id
WHERE (product_views.pv_date BETWEEN dateVal AND dateVal)
AND (products_likes.pl_date BETWEEN dateVal AND dateVal)
GROUP BY products.id
ORDER BY product_count
Perform the counts "per table" before joining otherwise you run the risk of getting larger results than there should be as joins can multiply the number of rows. Also, as there is a chance some products don't exist in likes or views so a left outer join to both of the "derived tables" is recommended.
SELECT
p.product_id
, (IFNULL(p.comment_count,0) + IFNULL(pv.view_count, 0) + IFNULL(pl.like_count, 0)) AS total
FROM products p
LEFT OUTER JOIN (
SELECT
product_id
, SUM(`count`) AS view_count
FROM products_views
WHERE `date` BETWEEN '2015-01-01' AND '2015-01-03'
GROUP BY
product_id
) pv ON p.product_id = pv.product_id
LEFT OUTER JOIN (
SELECT
product_id
, SUM(`count`) AS like_count
FROM products_likes
WHERE `date` BETWEEN '2015-01-01' AND '2015-01-03'
GROUP BY
product_id
) pl ON p.product_id = pl.product_id
GROUP BY
p.product_id
ORDER BY
total DESC
btw: date and count are reserved words in most SQL dialects; it not a good idea to name columns as date or count; use something more e.g. date_entered, date_created, view_count, like_count etc.
select p.product_id, sum(p.comment_count) + sum(v.count) + sum(l.count) as total from products p join products_views v on p.product_id = v.product_id join products_likes l on p.product_id = l.product_id group by p.product_id
where l.date between '2015-01-01' and '2015-01-03'
order by total desc
try this

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

SQL query statement table joins

I have a problem with a SQL query and the resultset being returned not being what I expected.
I have these three tables that I am trying to relate.
events_detail
__________________
| ID | start_date |
| 1 | 2012-08-09 |
| 2 | 2013-02-13 |
| 3 | 2012-12-12 |
| 4 | 2013-01-21 |
| 5 | 2012-12-25 |
-------------------
where ID is the primary key
events_category_relationship
__________________________
| ID | event_id | cat_id |
| 1 | 1 | 1 |
| 2 | 2 | 4 |
| 3 | 3 | 2 |
| 4 | 4 | 2 |
| 5 | 5 | 3 |
--------------------------
where ID is primary key
events_category_detail
__________________________________
| ID | name | description |
| 1 | Europe | Kings and castles! |
| 2 | USA | Freedoms |
| 3 | China | Made in China |
| 4 | UK | Big Brother |
------------------------------------
where ID is primary key
What I need to do is grab only 1 event from each category and sorted by date of earliest appearance. So what I should expect in my result is the following
Result Set
________________________________________________________________
| e_id | start_date | c_id | category_name | category_desc |
| 1 | 2012-08-09 | 1 | Europe | Kings and castles! |
| 3 | 2012-12-12 | 2 | USA | Freedoms |
| 5 | 2012-12-25 | 3 | China | Made in China |
| 2 | 2013-02-13 | 4 | UK | Big Brother |
-----------------------------------------------------------------
My SQL query that I tried looks like this
SELECT e.id, e.start_date, c.category_name, c.category_desc
FROM events_detail e
JOIN events_category_relationship r ON r.event_id = e.id
JOIN events_category_detail c ON c.id = r.cat_id
ORDER BY date(e.start_date)
This just joins the 3 tables and returns the result in order by date. What I am stuck on is making it so that only one of each category is displayed like the desired result set above. I have tried using DISTINCT c.category_name and GROUP BY c.category_name, but none of them works.
Any help or advice will be greatly appreciated.
You will want to use a subquery to get the min(start_date) for each name and description. You will then use this result to join back to your events_details table to get the id associated with the data in the subquery:
SELECT e.id,
d.start_date,
d.name,
d.description
FROM events_detail e
INNER JOIN
(
select min(e.start_date) Start_date,
c.name,
c.description
from events_detail e
INNER JOIN events_category_relationship r
ON r.event_id = e.id
INNER JOIN events_category_detail c
ON c.id = r.cat_id
group by c.name, c.description
) d
on e.start_date = d.Start_date
ORDER BY date(e.start_date)
See SQL Fiddle with Demo

Categories