I'm looking for a query to get monthly net sales I tried this far but I couldn't get what I want.
this is my Order Table
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| orderID | custID | userID | orderDate | paymentMethod | grossAmount | netAmount | cash | balance |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| INV-0001 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 525.00 | 525.00 | 550.00 | 25.00 |
| INV-0002 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 240.00 | 240.00 | 250.00 | 10.00 |
| INV-0003 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 220.00 | 220.00 | 250.00 | 30.00 |
| INV-0004 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 895.00 | 895.00 | 1000.00 | 105.00 |
| INV-0005 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 300.00 | 300.00 | 500.00 | 200.00 |
| INV-0006 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 230.00 | 230.00 | 250.00 | 20.00 |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
This is my CustomerReturn Table
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| retID | orderID | itemCode | userID | retDate | returnQty | unitPrice | totalAmount |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| 1 | INV-0001 | 1800232050 | U-001 | 2020-05-01 | 1.00 | 100.00 | 100.00 |
| 2 | INV-0002 | 1909873674 | U-001 | 2020-05-01 | 2.00 | 55.00 | 110.00 |
| 3 | INV-0004 | 1800232050 | U-001 | 2020-04-30 | 1.00 | 100.00 | 100.00 |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
the formula is (total of the monthly bill(Order.netAmount) - a total of monthly return (CustomerReturn.totalAmount))
in need to get net sales every year of every month.
select orderDate,sum(netAmount)-sum(totalAmount) from `Order` o,CustomerReturn r where o.orderID=r.orderID GROUP BY orderDate;
when I run this query it shows me this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 795.00 |
| 2020-05-01 | 555.00 |
+------------+---------------------------------+
but it should be Like this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 1425.00 |
| 2020-05-01 | 775.00 |
+------------+---------------------------------+
please help me. Thank you.!
Your query is good, it is fetching all records when there is a match on OrderId in the table CustomerReturn and doing the sums as you requested, however there are no returns for the order INV-0003, so this condition o.orderID=r.orderID is not valid when it comes to that record and it is ignoring that data. Doing a left join will fix the issue.
select
o.orderDate,
sum(o.netAmount)-sum(case when cr.totalAmount is null then 0 else cr.totalAmount end)
from
Orders o
left join
CustomerReturn cr
on
o.orderID = cr.orderID
group by
o.orderDate
A left join will cause cr.totalAmount to have null values in case there is no match for o.orderID=r.orderID then we use this part; case when cr.totalAmount is null then 0 else cr.totalAmount end to fix that null issue.
Because you are joining on dates that is why you are not getting correct answer, as order date and return date can have different month.
Better if you extract the month and then do sum as shown in below query, and here is the demo.
select
o.mm as month,
sum(total_net_amount - total_amount) as total
from
(
select
month(orderDate) as mm,
sum(netAmount) as total_net_amount
from Orders
group by
month(orderDate)
) o
join
(
select
month(retDate) as mm,
sum(totalAmount) as total_amount
from CustomerReturn
group by
month(retDate)
) cr
on o.mm = cr.mm
group by
o.mm
Output:
*--------------*
|month | total |
*--------------*
| 5 | 775 |
| 4 | 1325 |
*--------------*
Learn to use proper, explicit, standard, readable JOIN syntax. As pointed out in another answer, you want a LEFT JOIN. That said, the simpler way to write the logic is:
select o.orderDate,
sum(o.netAmount)- coalesce(sum(cr.totalAmount, 0)) as net_amount
from Orders o left join
CustomerReturn cr
on o.orderID = cr.orderID
group by o.orderDate;
Related
I have been working on this for about two days now and cant seem to figure it out so I would love some help.
I have two tables:
mysql> select id, date, volume, symbol_id from control_quotedaily limit 5;
+-------+---- -------+----------+-----------+
| id | date | volume | symbol_id |
+-------+------------+----------+-----------+
| 13263 | 2017-11-02 | 7800191 | AXISBANK |
| 13264 | 2017-11-02 | 9303981 | SBIN |
| 13265 | 2017-11-02 | 8013536 | HDFCBANK |
| 13266 | 2017-11-03 | 9642624 | AXISBANK |
| 13267 | 2017-11-04 | 19642327 | AXISBANK |
+-------+------------+----------+-----------+
5 rows in set (0.00 sec)
14 rows in set (0.01 sec)
mysql> select * from control_oidaily
+-----------+------------+-------------+--------------+
| symbol_id | date | expiry_date | val_in_lakhs |
+-----------+------------+-------------+--------------+
| AXISBANK | 2017-11-02 | 2017-11-30 | 166881.8 |
| AXISBANK | 2017-11-02 | 2017-12-28 | 2676.84 |
| AXISBANK | 2017-11-02 | 2018-01-25 | 97.13 |
| HDFCBANK | 2017-11-02 | 2017-11-30 | 76351.11 |
| HDFCBANK | 2017-11-02 | 2017-12-28 | 1509.48 |
| HDFCBANK | 2017-11-02 | 2018-01-25 | 0 |
| SBIN | 2017-11-02 | 2017-11-30 | 88654.3 |
| SBIN | 2017-11-02 | 2017-12-28 | 1060.51 |
| SBIN | 2017-11-02 | 2018-01-25 | 0 |
| AXISBANK | 2017-11-03 | 2017-11-30 | 87640.06 |
+-----------+------------+-------------+--------------+
So for every quote in the control_quotedaily table this is what I want:
closest expiry_date for that quote from the control_oidaily table
I want the val_in_lakhs for that expiry_date.
Eg: For date 2017-11-02, the closest expiry is 2017-11-30 and I want the val_in_lakhs (76351.11) returned.
This is what I am trying:
select o.date, o.expiry_date as expiry_date, o.symbol_id, q.date, q.symbol_id, o.val_in_lakhs, q.tottrdval, q.volume, q.symbol_id
FROM control_oidaily o
JOIN ( select o.date, MIN(expiry_date) as expiry_date, symbol_id
FROM control_oidaily o
GROUP by o.date,o.symbol_id
ORDER BY o.date asc) as ed
ON ed.date = o.date
AND ed.symbol_id = o.symbol_id
AND ed.expiry_date = o.expiry_date
JOIN control_quotedaily q
ON q.date = ed.date
AND q.symbol_id = ed.symbol_id
This is the output I am expecting:
+-------+------------+----------+-----------+--------------+--------------+
| id | date | volume | symbol_id | expiry_date | val_in_lakhs |
+-------+------------+----------+-----------+--------------+--------------+
| 13263 | 2017-11-02 | 7800191 | AXISBANK | 2017-11-30 | 166881.8 |
| 13264 | 2017-11-02 | 9303981 | SBIN | 2017-11-30 | 88654.3 |
| 13265 | 2017-11-02 | 8013536 | HDFCBANK | 2017-11-30 | 76351.11 |
| 13266 | 2017-11-03 | 9642624 | AXISBANK | 2017-11-30 | 87640.06 |
+-------+------------+----------+-----------+--------------+--------------+
In a Derived Table, get the closest_expiry_date (minimum value of expiry_date), for a grouping of symbol_id and date, from control_oidaily table.
Join this with the control_quotedaily table on symbol_id and date, to get closest_expiry_date value for every row in the control_quotedaily table.
Now, use the same derived table again to join with control_oidaily table, matching up on date, expiry_date (with closest expiry date) and symbol_id to get val_in_lakhs.
You possibly want the following query:
SELECT q.id,
q.`date`,
q.volume,
q.symbol_id,
o1.expiry_date,
o1.val_in_lakhs
FROM control_quotedaily AS q
JOIN (SELECT o2.`date`,
o2.symbol_id
MIN(o2.expiry_date) as closest_expiry_date
FROM control_oidaily AS o2
GROUP by o2.`date`, o2.symbol_id
) AS dt
ON dt.`date` = q.`date`
AND dt.symbol_id = q.symbol_id
JOIN control_oidaily AS o1
ON dt.`date` = o1.`date`
AND dt.symbol_id = o1.symbol_id
AND dt.closest_expiry_date = o1.expiry_date
Sample data:
db1.locationDetails table
| id | locationUID | locationName |
|----|-------------|--------------|
| 1 | L0001 | Site A |
| 2 | L0002 | Site B |
| 3 | L0003 | Site C |
| 3 | L0004 | Site D |
db2.HealthData table
| id | locationID | Date_Time | memUsage |
|----|-------------|------------------|----------|
| 1 | L0001 | 2018-09-10 11:43 | 35 |
| 2 | L0002 | 2018-09-10 08:22 | 39 |
| 3 | L0003 | 2018-09-10 14:44 | 43 |
| 4 | L0004 | 2018-09-10 16:01 | 72 |
| 5 | L0001 | 2018-09-12 01:26 | 50 |
| 6 | L0002 | 2018-09-12 03:15 | 32 |
I have a query:
SELECT DISTINCT db1.locationDetails.locationUID,
db1.locationDetails.locationName,
MAX(db2.HealthData.Date_Time),
db2.HealthData.memUsage,
IF(DATE(db2.HealthData.Date_Time) = '2018-09-12', "ON", "OFF") AS Status
FROM db1.locationDetails
LEFT JOIN db2.HealthData
ON db1.locationDetails.locationUID = db2.HealthData.locationID
GROUP BY db1.locationDetails.locationUID
Based on my understanding, the 'Status' column will show "ON" if the Date is equals to 2018-09-12 but somehow it always returns "OFF" regardless of whether the value in the Date_Time column is equal to the Date value specified in the query.
Can anyone tell me what is wrong here? Thanks in advance.
Expected output:
| locationUID | locationName | Date_Time | memUsage | Status |
|-------------|--------------|-----------------|----------|--------|
| L0001 | Site A |2018-09-12 01:26 | 50 | ON |
| L0002 | Site B |2018-09-12 03:15 | 32 | ON |
| L0003 | Site C |2018-09-10 14:44 | 43 | OFF |
| L0004 | Site D |2018-09-10 16:01 | 72 | OFF |
Use subquery to get your desired result:
select x.locationuid,x.locationname,maxitme, memusage, case when date(maxtime)='2018-09-12' then 'ON' else 'OFF' end as status
from db1.locationDetails x
inner join
(select a.locationuid,maxtime,memusage
from
(SELECT locationUID,MAX(Date_Time) as maxtime FROM db2.HealthData group by locationUID)a
inner join db2.HealthData b on a.locationuid=b.locationuid)y
on x.locationuid=y.locationuid
add Group by db1.locationDetails.locationUID,db2.HealthData.id
SELECT DISTINCT db1.locationDetails.locationUID,
db1.locationDetails.locationName,
MAX(db2.HealthData.Date_Time),
db2.HealthData.memUsage,
IF(DATE(db2.HealthData.Date_Time) = '2018-09-12', "ON", "OFF") AS Status
FROM db1.locationDetails
LEFT JOIN db2.HealthData
ON db1.locationDetails.locationUID = db2.HealthData.locationID
GROUP BY db1.locationDetails.locationUID,db2.HealthData.id
I'm trying to solve a question where each worker from a specific department sells a product and makes 1000 in profit. I want to find out the profit or loss of the company for each month. Assuming that the only profit comes from the sales and costs are the salaries off all workers.
Table dept_worker
+-----------+---------+------------+------------+
| worker_id | dept_n | from_date | to_date |
+-----------+---------+------------+------------+
| 10002 | 25 | 1996-08-03 | 9999-01-01 |
| 10016 | 25 | 1998-02-11 | 9999-01-01 |
| 10034 | 25 | 1995-04-12 | 1999-10-31 |
+-----------+---------+------------+------------+
Table salaries
+----------+--------+------------+------------+
| worker_id| salary | from_date | to_date |
+----------+--------+------------+------------+
| 10001 | 617 | 1986-04-26 | 1987-06-26 |
| 10002 | 600 | 1996-08-03 | 9999-01-01 |
| 10016 | 602 | 1998-02-11 | 9999-01-01 |
| 10034 | 674 | 1995-04-12 | 1999-10-31 |
| 10100 | 900 | 2000-07-25 | 2002-06-25 |
+----------+--------+------------+------------+
I tried two different approaches. I tried using WHERE dept_n = '25' but the result wasn't the expected because I was filtering everything.
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id)*1000 AS 'Profit',
SUM (salary) AS 'Costs', (COUNT(worker_id)*1000-SUM(salary)) AS 'Diff'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY Month
ORDER BY Diff DESC;
The second one (this query doesn't give me any result):
SELECT MONTH(from_date) AS 'Months',
(SELECT COUNT(worker_id)*1000 FROM dept_worker WHERE dept_n = '25') AS 'Profits', SUM(salary)
FROM dept_worker JOIN salaries using(from_date)
GROUP BY Months;
Expected result:
+----------+--------+------------+-------------------+
| Months | Profits| Costs | Profits - Costs |
+----------+--------+------------+-------------------+
| 1 | 4456 |14478 |-10022 |
| 2 | 4105 |14824 |-10719 |
| 3 | 4379 |16130 |-11751 |
| 4 | 4329 |15562 |-11233 |
| (...) | (...) |(...) |(...) |
+----------+--------+------------+-------------------+
Try Starting with this:
SELECT MONTH(from_date) AS 'Months', COUNT(worker_id) over(partition by dept_n order by dept_n) * 1000 AS 'Profit',
SUM (salary) over(partition by dept_n order by dept_n) AS 'Costs'
FROM dept_worker JOIN salaries using(from_date,worker_id)
GROUP BY MONTH(from_date)
Consider this excerpt of our Users table:
+-------------+---------------------+---------------------+
| id | last_login | created |
+-------------+---------------------+---------------------+
| 14551578822 | 2014-02-22 17:38:39 | 2013-03-26 23:30:50 |
| 18442388426 | 0000-00-00 00:00:00 | 2013-11-07 15:51:11 |
| 49983341634 | 2014-03-06 22:28:47 | 2013-03-23 16:00:05 |
| 9527246957 | 2014-01-17 02:37:53 | 2013-05-14 02:14:49 |
| 58667409337 | 2014-03-08 06:54:01 | 2013-05-15 01:52:23 |
| 1907780002 | 2014-03-01 03:24:04 | 2013-05-01 07:57:56 |
| 65319490251 | 2014-03-19 05:49:41 | 2013-03-23 08:53:43 |
| 23896465717 | 0000-00-00 00:00:00 | 2012-10-21 10:52:23 |
| 19147401900 | 0000-00-00 00:00:00 | 2013-05-01 17:43:28 |
| 28598429318 | 0000-00-00 00:00:00 | 2014-03-14 14:44:15 |
+-------------+---------------------+---------------------+
We have many, many users - and we would like to generate a report that will display the total number of users we have as the date increases. We would like output similar to this:
+---------+---------------+
| DATE | User Count |
+---------+---------------+
| 2012-08 | 122 |
| 2012-09 | 1746 |
| 2012-10 | 3847 |
| 2012-11 | 5826 |
...
| 2014-03 | 472647 |
| 2014-04 | 497286 |
+---------+---------------+
There must be some way to do it without subselects and all kinds of messiness like that. I have a table already that displays the number of joins per period by the following query:
SELECT DATE(users.created) as JOIN_DATE , COUNT(users.id) AS JOIN_COUNT from users
WHERE users.created > '2012-07-01 00:00:00'
GROUP BY JOIN_DATE
ORDER BY JOIN_DATE ASC
Just wondered if there was a way to do it something like that.
Thanks!
You can use a variable to sum up the population foreach iteration
SELECT t.date ,
#population := #population+t.per_time population
FROM (
SELECT
DATE_FORMAT(`last_login` ,'%Y-%m') `date`,
COUNT(*) per_time
FROM Table1
WHERE created > '2012-07-01 00:00:00'
GROUP BY `date` ) t ,
(SELECT #population:=0) p
Fiddle Demo
I'm building a stock keeping system and decided to store each product's balance (everytime it's updated) into the following table:
+------------+--------------+---------+------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+------+
Example:
Staff adds 10 pieces to product_id 123 in warehouse_id 5
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
+------------+--------------+---------+-------------+
Staff then adds 3 pieces to product 234 in warehouse_id 5, and
5 pieces to 123 in warehouse_id 5,
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 15 | 2013-09-21 |
+------------+--------------+---------+-------------+
*Notice the date column
Now let me add a few more rows
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 123 | 5 | 10 | 2013-09-16 |
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 15 | 2013-09-21 |
| 123 | 5 | 18 | 2013-09-24 |
| 234 | 5 | 10 | 2013-09-26 |
| 123 | 5 | 22 | 2013-09-29 |
+------------+--------------+---------+-------------+
How do i run a query that would get me all products' balances as at 25th of September 2013?
That means i need the following result:
+------------+--------------+---------+-------------+
| Product_id | Warehouse_id | Balance | Date |
+------------+--------------+---------+-------------+
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 18 | 2013-09-24 |
+------------+--------------+---------+-------------+
In short I need the latest row (by date), per product_id.
Any help would be greatly appreciated!
Assuming that products' balances are being maintained per warehouse you can do it like this
SELECT t.product_id, t.warehouse_id, t.balance, t.date
FROM table1 t JOIN
(
SELECT warehouse_id, product_id, MAX(date) date
FROM table1
WHERE date <= '2013-09-25'
GROUP BY warehouse_id, product_id
) q
ON t.warehouse_id = q.warehouse_id
AND t.product_id = q.product_id
AND t.date = q.date
Output:
| PRODUCT_ID | WAREHOUSE_ID | BALANCE | DATE |
|------------|--------------|---------|------------|
| 234 | 5 | 3 | 2013-09-18 |
| 123 | 5 | 18 | 2013-09-24 |
Here is SQLFiddle demo
SELECT *
FROM TABLE
WHERE (PRODUCT_ID, DATE) IN
(SELECT PRODUCT_ID, MAX(DATE) FROM TABLE
WHERE DATE <= '2013-09-25'
GROUP BY PRODUCT_ID )
Query:
SQLFIDDLEExample
SELECT *
FROM table1 t
WHERE t.`Date` = (SELECT MAX(t2.`Date`)
FROM Table1 t2
WHERE t2.`Date` <= '2013-09-25'
AND t2.product_id = t.product_id)