mysql display each day data for specified date range - mysql

Query:-Display customername,total_return in last 7 days,and quantity_sold to the customer for the last 7 days with
each day representing a column,as follows,i did till first 3 columns.
But i don't know how to display data for each particular day or date.
customername total_retuns total_sold t_6 t_5 t_4 t_3 t_2 t_1 t
---------------------------------------------------------------------------------
karan | 80 | 200 | | | | | | | |
hemanth | 90 | 300
--------------------------------------------------------------------------------
Select Query:
select c.Name,sum(od.return_quantity) totalReturns,
sum(od.quantity_sold) quantitySold from customer c
left join orders o on c.CustomerId=o.CustomerId
left join order_details od on o.OrderId=od.orderid
where o.OrderedDate between curdate()-6 and curdate()
group by c.Name order by totalreturns;

Related

Getting wrong sum when using group by with inner join

With reference to this question (How to get the sum in a joined table when using group by - getting wrong results) I have two tables orders and order_items. I need to group the results by days. But I also need to get the sum of energy_used for each day from another table. When I try that using a join, I get wrong order_sum for each day (they are not being summed up). Not sure what I am doing wrong.
I would like to get for each day
the sum of order_items.energy_used for all orders created that day
the sum of orders.order_sum for all orders created that day
the created_at and order_sum that correspond to the latest order created on that day
Here is my orders table
+----+-----------+---------+---------------------+
| id | order_sum | user_id | created_at |
+----+-----------+---------+---------------------+
| 1 | 25.13 | 7 | 2020-01-25 09:13:00 |
| 2 | 10.00 | 7 | 2020-01-25 15:23:00 |
| 3 | 14.00 | 5 | 2020-01-26 10:14:00 |
| 4 | 35.00 | 1 | 2020-01-27 11:13:00 |
+----+-----------+---------+---------------------+
And here is my order_items table
+----+----------+-------------+---------------------+
| id | order_id | energy_used | created_at |
+----+----------+-------------+---------------------+
| 1 | 1 | 65 | 2020-01-25 09:13:00 |
| 2 | 1 | 12 | 2020-01-25 09:13:00 |
| 3 | 2 | 70 | 2020-01-26 10:14:00 |
| 4 | 2 | 5 | 2020-01-26 10:14:00 |
| 5 | 3 | 0 | 2020-01-27 11:13:00 |
+----+----------+-------------+---------------------+
And this is the desired result that I am trying to achieve
+---------------+-----------------+-------------------+---------------------+----------------+
| date_of_month | total_order_sum | total_energy_used | last_order_date | last_order_sum |
+---------------+-----------------+-------------------+---------------------+----------------+
| 2020-01-25 | 35.13 | 77 | 2020-01-25 09:13:00 | 25.13 |
| 2020-01-26 | 14.00 | 75 | 2020-01-26 10:14:00 | 14.00 |
| 2020-01-27 | 35.00 | 0 | 2020-01-27 11:13:00 | 35.00 |
+---------------+-----------------+-------------------+---------------------+----------------+
And here is the query that I have tried but I'm getting wrong results, the order_sum is not being calculated correctly. It is showing the same as last_order_sum
select
date(o.created_at) date_of_month,
i.total_energy_used,
o.created_at last_order_date,
o.order_sum last_order_sum,
sum(order_sum) as total_order_sum
from orders o
inner join (
select date(o1.created_at) date_of_month, sum(i1.energy_used) total_energy_used
from orders o1
inner join order_items i1 on o1.id = i1.order_id
group by date(o1.created_at)
) i on i.date_of_month = date(o.created_at)
where o.created_at = (
select max(o1.created_at)
from orders o1
where date(o1.created_at) = date(o.created_at)
)
Here is a fiddle:
https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=92b8cc2920ad9f7a7cdd56bded5a3bf2
Always join tables together on their relationships (in this case orders.id with order_items.order_id) and then group. to avoid duplicating order_sums for multiple order_items when joining, first group order_items by order_id.
select
date(o.created_at) date_of_month,
sum(i.total_energy_used),
max(o.created_at),
sum(order_sum) as total_order_sum
from orders o
inner join (
select order_id, sum(total_energy_used) total_energy_used
from order_items i
group by order_id
) i on o.id = i.order_id
group by date(o.created_at)
from this point onwards you can do a join again on orders with max(o.created_at) to get the order_sum of the last order.
moral of the story: keep an eye on your granularity.
Your problem is that you are selecting from orders, where you actually want an aggregate of orders by date. So select from two aggregtating subqueries that you join. Only problem is last_order_sum, which we can select in a further subquery, once we know the last order date.
select
order_date,
o.total_order_sum,
oi.total_energy_used,
o.last_order_date,
(
select order_sum
from orders last_order
where lastorder.created_at = o.last_order_date
) as last_order_sum
from
(
select
date(created_at) as order_date,
sum(order_sum) as total_order_sum,
max(created_date) as last_order_date
from orders
group by date(created_at)
) o
inner join
(
select
date(created_at) as order_date,
sum(energy_used) as total_energy_used
from order_items
group by date(created_at)
) oi using(order_date)
order by order_date;
What you are asking and what you show us in output are not correlated. Assuming that it is a typo:
select so.dtDay as date_of_month, so.order_sum as total_order_sum,
eu.energy_used as total_energy_used,
o.created_at as last_order_date,
o.order_sum as last_order_sum
from (
select left(created_at,10) as dtDay, sum(order_sum) as order_sum, max(id) as last_insert_id
from orders
group by left(created_at,10)
order by created_at
) so
inner join orders o on o.id = so.last_insert_id
left join (select left(created_at,10) as dtDay, sum(energy_used) as energy_used
from order_items
group by left(created_at,10)) eu on so.dtDay = eu.dtDay;
DBFiddle

How to join two tables with average function and where clause? SQL

I have two tables below with the following information
project.analytics
| proj_id | list_date | state
| 1 | 03/05/10 | CA
| 2 | 04/05/10 | WA
| 3 | 03/05/10 | WA
| 4 | 04/05/10 | CA
| 5 | 03/05/10 | WA
| 6 | 04/05/10 | CA
employees.analytics
| employee_id | proj_id | worked_date
| 20 | 1 | 3/12/10
| 30 | 1 | 3/11/10
| 40 | 2 | 4/15/10
| 50 | 3 | 3/16/10
| 60 | 3 | 3/17/10
| 70 | 4 | 4/18/10
What query can I write to determine the average number of unique employees who have worked on the project in the first 7 days that it was listed by month and state?
Desired output:
| list_date | state | # Unique Employees of projects first 7 day list
| March | CA | 1
| April | WA | 2
| July | WA | 2
| August | CA | 1
My Attempt
select
month(list_date),
state_name,
count(*) as Projects,
from projects
group by
month(list_date),
state_name;
I understand the next steps are to subtract the worked_date - list_date and if value is <7 then average count of employees from the 2nd table but I'm not sure what query functions to use.
You could use a CASE with a DISTINCT to COUNT the unique employees that worked within the first 7 days of the list_date.
Once you have that total of employees per project, then you can calculate those averages per month & state.
SELECT
MONTHNAME(list_date) as `ListMonth`,
state,
AVG(TotalUniqEmp7Days) AS `Average Unique Employees of projects first 7 day list`
FROM
(
SELECT
proj.proj_id,
proj.list_date,
proj.state,
COUNT(DISTINCT CASE
WHEN emp.worked_date BETWEEN proj.list_date and DATE_ADD(proj.list_date, INTERVAL 6 DAY)
THEN emp.employee_id
END) AS TotalUniqEmp7Days
-- , COUNT(DISTINCT emp.employee_id) AS TotalUniqEmp
FROM project.analytics proj
LEFT JOIN employees.analytics emp ON emp.proj_id = proj.proj_id
GROUP BY proj.proj_id, proj.list_date, proj.state
) AS ProjectTotals
GROUP BY YEAR(list_date), MONTH(list_date), MONTHNAME(list_date), state;
A Sql Fiddle test can be found here
I think this is the code that you want
select
p.list_date, p.state,
emp.no_of_unique_emp
from project.analytics p
inner join (
select
t.project_id,
count(t.employee_id) as no_of_unique_emp
from (
select distinct employee_id, project_id
from employees.analytics
) t
group by t.project_id
) emp
on emp.project_id = p.project_id
where datediff (p.list_date, getdate()) <= 7

Get SUM of two fields in 2 different related tables

I'd like to get the SUM of the amount column in two related tables.
Invoices Table:
-----------------------------------------
| id | student_id | created | updated |
-----------------------------------------
| 5 | 25 | date | date |
-----------------------------------------
Invoice Items Table:
------------------------------
| id | invoice_id | amount |
------------------------------
| 1 | 5 | 250 |
------------------------------
| 2 | 5 | 100 |
------------------------------
| 3 | 5 | 40 |
------------------------------
Payments Table:
------------------------------
| id | invoice_id | amount |
------------------------------
| 1 | 5 | 100 |
------------------------------
| 2 | 5 | 290 |
------------------------------
Desired Output:
--------------------------------------
| id | invoiceTotal | paymentTotal |
--------------------------------------
| 1 | 390 | 390 |
--------------------------------------
The query I've tried
SELECT
i.id,
sum(ii.amount) as invoiceTotal,
sum(p.amount) as paymentTotal
FROM
invoices i
LEFT JOIN
invoice_items ii ON i.id = ii.invoice_id
LEFT JOIN
payments p ON i.id = p.invoice_id
WHERE
i.student_id = '25'
GROUP BY
i.id
What this seems to do is calculate the sum of the payments properly but the invoice_items.amount appears to have been duplicated by 6 (which is the number of payments there are).
I have read similar questions on SO here and here but the examples are so much more complex than what I'm trying to do and I can't figure out what to put where.
The join causes a problem with cartesian products. If a student has multiple invoice items and payments, then the totals will be wrong.
One approach that works best for all invoices is a union all/group by approach:
select i.id, sum(invoiceTotal) as invoiceTotal, sum(paymentTotal) as paymentTotal
from ((select i.id, 0 as invoiceTotal, 0 as paymentTotal
from invoices i
) union all
(select ii.invoiceId, sum(ii.amount) as invoiceTotal, NULL
from invoiceitems ii
group by ii.invoiceId
) union all
(select p.invoiceId, 0, sum(p.amount) as paymentTotal
from payments p
group by p.invoiceId
)
) iip
group by id;
For a single student, I would recommend correlated subqueries:
select i.id,
(select sum(ii.amount)
from invoiceitems ii
where ii.invoiceid = i.id
) as totalAmount,
(select sum(p.amount)
from payment p
where p.invoiceid = i.id
) as paymentAmount
from invoices i
where i.studentid = 25;

How to SUM column in MySQL left join

So i have table cont_selling
---------------------------------
cont_selling_id | date |
---------------------------------
1 | 2015-05-24 |
2 | 2015-06-06 |
---------------------------------
table 02 cont_sold
----------------------------------------------------
cont_sold_id | cont_selling_id | price |
---------------------------------------------------
1 | 1 | 10 |
2 | 1 | 10 |
3 | 1 | 30 |
4 | 2 | 20 |
5 | 2 | 10 |
--------------------------------------------------
and table 03 payment
----------------------------------------------
payment_id | cont_selling_id | paid |
-----------------------------------------------
1 | 1 | 10 |
2 | 2 | 10 |
3 | 1 | 20 |
4 | 1 | 10 |
5 | 2 | 10 |
-----------------------------------------------
now i need to SELECT table based on
now i want to merge all these three tables based on cont_selling table cont_selling_id column
and want to SUM cont_sold table price column and payment table paid column
this is what i want to do
expecting output
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 50 | 40 |
2 | 30 | 20 |
---------------------------------------------
so i tried like this in mysql query but it give wrong sum result
SELECT
SUM(Z.price) as total,
SUM(P.amount) as paid
FROM cont_selling S
LEFT JOIN cont_sold Z
ON S.cont_selling_id = Z.cont_selling_id
LEFT JOIN payment P
ON S.cont_selling_id = P.cont_selling_id
GROUP BY S.cont_selling_id
for this above query i m getting output like this
---------------------------------------------
cont_selling_id | price | paid |
---------------------------------------------
1 | 150 | 40 |
2 | 60 | 120 |
---------------------------------------------
Here how you can do it using the aggegare part into inner queries and then join
select
cs.cont_selling_id,
price,
paid
from cont_selling cs
left join(
select sum(price) as price , cont_selling_id from cont_sold
group by cont_selling_id
)x on x.cont_selling_id = cs.cont_selling_id,
left join(
select sum(paid) as paid , cont_selling_id from payment
group by cont_selling_id
)y
on y.cont_selling_id = cs.cont_selling_id;
You should make two different queries with SUM and then combine them to get the desired result:
SELECT T1.cont_selling_id,T1.price,T2.paid
FROM
(SELECT c.cont_selling_id,SUM(cs.price) as price
FROM cont_selling c LEFT JOIN
cont_sold cs ON c.cont_selling_id=cs.cont_selling_id
GROUP BY c.cont_selling_id) as T1 JOIN
(SELECT c.cont_selling_id,SUM(p.paid) as paid
FROM cont_selling c LEFT JOIN
payment p ON p.cont_selling_id=c.cont_selling_id
GROUP BY c.cont_selling_id) as T2 ON T1.cont_selling_id=T2.cont_selling_id
Result:
cont_selling_id price paid
----------------------------
1 50 40
2 30 20
Sample result in SQL Fiddle.
This untested query should work:
with a as(select cont_selling_id , sum(price) as totalprice from cont_sold group by cont_selling_id),
with a as(select cont_selling_id , sum(paid) as totalpaid from payment group by cont_selling_id),
select c.cont_selling_id , totalprice, totalpaid from cont_selling c left join a.count_selling_id = c.count_selling_id
left join b.count_selling_id = c.count_selling_id
You have to create temporary tables, because there is no dependency between your table for price and paid.

MySql LEFT JOIN with COUNT

I have two tables, customers and sales. I want to count sales for each customer and create a table of sales per month for each store.
I would like to produce something like;
------------------------------
month | customers | sales |
------------------------------
1/2013 | 5 | 2 |
2/2013 | 21 | 9 |
3/2013 | 14 | 4 |
4/2013 | 9 | 3 |
but I am having trouble getting the sales count to be correct when using the following;
SELECT CONCAT(MONTH(c.added), '/', YEAR(c.added)), count(c.id), count(s.id)
FROM customers c
LEFT JOIN sales s
ON s.customer_id = c.id AND MONTH(c.added) = MONTH(s.added) AND YEAR(c.added) = YEAR(s.added)
WHERE c.store_id = 1
GROUP BY YEAR(c.added), MONTH(c.added);
Customers table;
-------------------------------
id | store_id | added |
-------------------------------
1 | 1 |2013-02-01 |
2 | 1 |2013-02-02 |
3 | 1 |2013-03-16 |
sales table;
---------------------------------
id | added | customer_id |
---------------------------------
1 | 2013-02-18 | 3 |
2 | 2013-03-02 | 2 |
3 | 2013-03-16 | 3 |
Can anyone help here?
thanks
(Updated) The existing query will only count sales made in the same month that the customer was added. Try this, instead:
SELECT CONCAT(MONTH(sq.added), '/', YEAR(sq.added)) month_year,
sum(sq.customer_count),
sum(sq.sales_count)
FROM (select s.added, 0 customer_count, 1 sales_count
from customers c
JOIN sales s ON s.customer_id = c.id
WHERE c.store_id = 1
union all
select added, 1 customer_count, 0 sales_count
from customers
WHERE store_id = 1) sq
GROUP BY YEAR(sq.added), MONTH(sq.added);
SELECT c.* , s.sales_count<br>
FROM customers c<br>
LEFT JOIN (SELECT customer_id, count(id) as sales_count FROM sales GROUP BY customer_id) s on c.id=s.customer_id<br>
WHERE c.store_id = 1<br>