Trouble in join and alias table - mysql

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)

Related

Retrieving data from the row containing the closest date to today with whereDate

I want to sort by price after filtering and grouping by date. However, because there are more than one relation, I cannot get the result I want.
The result I want is to get the price of the relation that is the closest to the end_date and sort it accordingly.
For this, the query, sql output, tables and demo page are as follows.
Thanks in advance ..
demo sqlfiddle
$query->join('tableB', 'tableA.id', '=', 'tableB.pro_id')
->select('tableA.*', 'tableB.start_date', 'tableB.end_date', 'tableB.old_daily')
->where(function($sq) {
$today = Carbon::now()->format('Y-m-d');
$sq->whereDate('end_date', '>=', $today);
})
->groupBy('tableA.id')
->orderBy('price', desc);
Query:
select `tableA`.*, `tableB`.`start_date`, `tableB`.`end_date`, `tableB`.`price`
from `tableA`
inner join `tableB` on `tableA`.`id` = `tableB`.`pro_id`
where (date(`end_date`) >= 2021-03-07)
group by `tableA`.`id`
order by `price` desc
tableA
| id | title |
|----|-------|
| 1 | pro1 |
| 2 | pro2 |
| 3 | pro3 |
tableB
| id | start_date | end_date | price | pro_id |
|----|------------|------------|-------|--------|
| 1 | 2021-06-01 | 2021-06-05 | 750 | 2 |
| 2 | 2021-05-01 | 2021-05-05 | 850 | 2 |
| 3 | 2021-04-01 | 2021-04-05 | 650 | 2 |
| 4 | 2021-06-01 | 2021-06-05 | 2750 | 1 |
| 5 | 2021-05-01 | 2021-05-05 | 2850 | 1 |
| 6 | 2021-04-01 | 2021-04-05 | 2650 | 1 |
| 7 | 2021-06-01 | 2021-06-05 | 1750 | 3 |
| 8 | 2021-05-01 | 2021-05-05 | 1850 | 3 |
| 9 | 2021-04-01 | 2021-04-05 | 1650 | 3 |
this query gives the result you want.
It would be a good choice to use "right join" in this step.
sqlfiddle
select `tableA`.*, `tableB`.`start_date`, `tableB`.`end_date`, `tableB`.`price`
from `tableA`
right join(
SELECT id, start_date, end_date, pro_id, price, DATEDIFF(`tableB`.`end_date`, '2021-03-07') diff
FROM `tableB`
GROUP BY id order by diff asc
) `tableB` on `tableA`.`id` = `tableB`.`pro_id`
where (date(`end_date`) >= '2021-03-07')
group by `tableA`.`id`
order by `price` desc
the closest to the end_date and sort it accordingly.
you should find the difference between the given date and end date then sort ascendingly.
ORDER BY DATEDIFF(end_date, '2021-03-07') ASC

SQL query to get Net Salse by every month

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;

select count in mysql on 2 fields to get aggregated result

I have a mysql Table.
+----+----------------+-----------+---------------+---------------------+
| id | transaction_id | user_id | book_id | purchase_date |
+----+----------------+-----------+---------------+---------------------+
| 52 | bq4ren25a8w0 | ABC_00002 | xxxx951410361 | 2017-04-25 12:30:18 |
| 66 | j4ax039ilc00 | ABC_00260 | xxxx951410392 | 2017-04-25 12:30:18 |
| 67 | s2a57kp4g000 | ABC_00260 | xxxx951410361 | 2017-06-05 12:28:56 |
| 68 | h4z4h80ts000 | ABC_00260 | xxxx951410415 | 2017-06-07 12:47:24 |
| 69 | 2bt7ipsf9sy3 | ABC_00262 | xxxx951410392 | 2017-06-05 13:25:10 |
| 70 | x0rlwhm00000 | ABC_00264 | xxxx951410392 | 2017-06-09 14:23:08 |
+----+----------------+-----------+---------------+---------------------+
I need a result whic is group by book_id + purchase_date such that
+---------------+---------------------+-------+
| book_id | purchase_date | count |
+---------------+---------------------+-------+
| xxxx951410361 | 2017-04-25 12:30:18 | 10 |
| xxxx951410392 | 2017-06-05 14:27:19 | 12 |
+---------------+---------------------+-------+
I dont have much exposure in mysql, I just tried
Select Count(book_id) as book_id, purchase_date
FROM tbl_name
GROUP BY book_id, purchase_date
Its not working.
Need some help
You can use DATE to group the purchases by days.
SELECT book_id,COUNT(book_id),DATE(purchase_date) AS pdate FROM book_sales GROUP BY book_id,pdate;
If you want to know how many books were sold on a specific day, you can use:
SELECT DATE(purchase_date) AS purchase_date,COUNT(DATE(purchase_date)) AS books FROM book_sales GROUP BY DATE(purchase_date);
http://sqlfiddle.com/#!9/4cde14/6
You can try like this, hope you will get what you need.
SELECT book_id, purchase_date,COUNT(purchase_date) as count
FROM book_sales
GROUP BY purchase_date;

Calculate sum for group records in MySQL

I have this table of orders
| ORDER_ID | PRODUCT | CUSTOMER | QTY | DATE
---------------------------------------------
| 1 | shoes | Nick | 1 | 01/01/2016
| 2 | shirts | Nick | 5 | 02/02/2016
| 3 | shoes | Paul | 10 | 03/03/2016
| 4 | shirts | Paul | 20 | 04/04/2016
So, How can I achieve this report result with ONE Select Statement?
| Date_of_Order | Customer | Quantity | PRODUCT_TOTAL_SALES |
-----------------------------------------------------------------
| 01/01/2016 | Nick | 1 | shoes : 11 |
| 02/02/2016 | Nick | 10 | shirts : 25 |
| 03/03/2016 | Paul | 5 | shoes : 11 |
| 04/04/2016 | Paul | 20 | shirts : 25 |
I know how to use concat(column1, ' ', column2) to create a combined column but I haven't succeed to add a sum for a grouped item there. When I try with left join I get the sum for a product ...BUT its always the whole sum and its not related to the dates of the order so when I try to filter the results on my query for a certain period I still get 11 for shoes and 25 for shirts...
You can group by multiple columns and get the sum for the smallest group.
If you want the daily sales, then instead of GROUP BY product use GROUP BY product, date
SELECT
o.`date` AS Date_of_Order,
SUM(o.qty) as Total_Quantity,
CONCAT(o.product, ':', SUM(o.qty))
FROM
orders o
GROUP BY product, `date`
ORDER BY `date`
Simple additional SELECT from same table can do that for entire period:
SELECT
o.`date` AS Date_of_Order,
o.Customer,
o.qty as Quantity,
(SELECT
CONCAT(oo.product, ':', SUM(oo.qty))
FROM
orders oo
WHERE
oo.product = o.product
) PRODUCT_TOTAL_SALES
FROM
orders o
Output:
+---------------+----------+----------+---------------------+
| Date_of_Order | Customer | Quantity | PRODUCT_TOTAL_SALES |
+---------------+----------+----------+---------------------+
| 01/01/2016 | Nick | 1 | shoes:11 |
| 02/02/2016 | Nick | 5 | shirts:25 |
| 03/03/2016 | Paul | 10 | shoes:11 |
| 04/04/2016 | Paul | 20 | shirts:25 |
+---------------+----------+----------+---------------------+
4 rows in set
If you want to filter by certain period, you must include it in both:
SELECT
o.`date` AS Date_of_Order,
o.Customer,
o.qty as Quantity,
(SELECT
CONCAT(oo.product, ':', sum(oo.qty))
FROM
orders oo
WHERE
oo.product = o.product
AND STR_TO_DATE(oo.`date`,'%d/%m/%Y') BETWEEN '2016-01-01' AND '2016-03-03'
) PRODUCT_TOTAL_SALES
FROM
orders o
WHERE
STR_TO_DATE(o.`date`,'%d/%m/%Y') BETWEEN '2016-01-01' AND '2016-03-03'
Output:
+---------------+----------+----------+---------------------+
| Date_of_Order | customer | Quantity | PRODUCT_TOTAL_SALES |
+---------------+----------+----------+---------------------+
| 01/01/2016 | Nick | 1 | shoes:11 |
| 02/02/2016 | Nick | 5 | shirts:5 |
| 03/03/2016 | Paul | 10 | shoes:11 |
+---------------+----------+----------+---------------------+
3 rows in set

MySQL Select one row with unique attribute value

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)