MySQL get different SUMs based on dates - mysql

I'm trying to create a Sql query where I can sums for 4 different date range.
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
Select
TenantID,
SUM(CASE WHEN TransactionTypeID = 1 AND ChargeTypeID != 6 THEN TransactionAmount ELSE 0 END) AS TotalDebit,
From TenantTransactions
Where TenantTransactionDate BETWEEN /* Here is my issue */
Group By TenantID
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
I am trying to return 4 sums:
For the last 30 days
For last 30-60 days
For last 60-90 days
Greater than 90 days ago
Does it make sense?
Thanks

You're looking for totals based on the age of the transaction. We can get that by subtracting the transaction date from today to get a result in days:
datediff(now(), TenantTransactionDate)
You want to group that into period by 30 days, so we use integer division to get a period:
datediff(now(), TenantTransactionDate) DIV 30
And lastly, you want everything over 90 days grouped together:
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3)
This last expression returns a value of 0, 1, 2 or 3. We can use that to group the transactions, and total them:
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
order by tenantID, period
Now you should be able to plug that back into your original query, and sort them:
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
order by t.tenantID, sums.period

Related

MySQL calculate percentage of two other calculated sums including a group by month

Say i have 3 tables with a model like this
The result i want to have now looks like this
I want to calculate turnovers and profits made by all employees per month and compare it to the last years SAME month and calculate the difference in percentage of the profits. It should include the last 12 months with the INTERVAL function.
select
bookings.b_emp_id as "Employee",
MONTH(bookings.b_date) as Month,
#turnover1 := sum(bookings.b_turnover) as '2017-turnover',
#turnover2 := (select sum(lx.b_turnover)
from bookings as lx
where lx.b_date = date_add(bookings.b_date, INTERVAL -1 YEAR)
GROUP BY
MONTH(bookings.b_date),
YEAR(bookings.b_date),
bookings.b_emp_id
) as '2016-turnover',
sum(b_profit) as '2017-profit',
#profit1 := (select sum(lx.umsatz_fees)
from bookings as lx
where lx.b_date = date_add(bookings.b_date,INTERVAL -1 YEAR)
GROUP BY
MONTH(bookings.b_date),
YEAR(bookings.b_date),
bookings.b_emp_id
) as '2016-profit'
from bookings
where bookings.b_date > '2017-01-01'
and bookings.b_emp_id = ´SA´
GROUP BY MONTH(bookings.b_date)
order by bookings.b_date desc
Use conditional aggregation. It is not clear if you want to look at the last 12 / 24 months, or at the months of 2017 and the same months in 2016. Neither do I understand how you want to calculate a percentage. I divide this year's profits by last year's in below query. Adjust this so it meets your needs.
select
b_emp_id,
month,
turnover_this_year,
profit_this_year,
turnover_last_year,
profit_last_year,
profit_this_year / profit_last_year * 100 as diff
from
(
select
b_emp_id,
month(b_date) as month,
sum(case when year(b_date) = year(curdate()) then b_turnover end) as turnover_this_year,
sum(case when year(b_date) = year(curdate()) then b_profit end) as profit_this_year,
sum(case when year(b_date) < year(curdate()) then b_turnover end) as turnover_last_year,
sum(case when year(b_date) < year(curdate()) then b_profit end) as profit_last_year
from bookings
where year(b_date) in (year(curdate()), year(curdate()) - 1)
and month(b_date) <= month(curdate())
group by b_emp_id, month(b_date)
) figures
order by b_emp_id, month;

MySql graph query multiple series aligned to same time x-axis

I have queries that I'm using to make a graph of earnings. But now people are able to earn from two different sources, so I want to separate this out into two lines on the same chart
This one for standard earnings:
SELECT DATE_FORMAT(earning_created, '%c/%e/%Y') AS day, SUM(earning_amount) AS earning_standard
FROM earnings
WHERE earning_account_id = ? AND earning_referral_id = 0 AND (earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
GROUP BY DATE(earning_created)
ORDER BY earning_created
And this one for referral earnings:
SELECT DATE_FORMAT(e.earning_created, '%c/%e/%Y') AS day, SUM(e.earning_amount) AS earning_referral
FROM earnings AS e
INNER JOIN referrals AS r
ON r.referral_id = e.earning_referral_id
WHERE e.earning_account_id = ? AND e.earning_referral_id > 0 AND (e.earning_created > DATE_SUB(now(), INTERVAL 90 DAY)) AND r.referral_type = 0
GROUP BY DATE(e.earning_created)
ORDER BY e.earning_created
How do I get it to run the queries together, so that it outputs two columns/series for the y-axis: earning_standard and earning_referral.
But with them both aligned to the same day column/scale for the x-axis - substituting zero when there are no earnings for a specific series.
You'll need to set both of those queries as subqueries
SELECT DATE_FORMAT(earnings.earning_created, '%c/%e/%Y') AS day,
COALESCE(es.earning_standard, 0) AS earning_standard,
COALESCE(er.earning_referral, 0) AS earning_referral
FROM earnings
LEFT JOIN (SELECT DATE_FORMAT(earning_created, '%c/%e/%Y') AS day,
SUM(earning_amount) AS earning_standard
FROM earnings
WHERE earning_account_id = ?
AND earning_referral_id = 0
AND (earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
GROUP BY DATE(earning_created)) AS es
ON (day = es.day)
LEFT JOIN (SELECT DATE_FORMAT(e.earning_created, '%c/%e/%Y') AS day,
SUM(e.earning_amount) AS earning_referral
FROM earnings AS e
INNER JOIN referrals AS r
ON r.referral_id = e.earning_referral_id
WHERE e.earning_account_id = ?
AND e.earning_referral_id > 0
AND (e.earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
AND r.referral_type = 0
GROUP BY DATE(e.earning_created)) AS er
ON (day = er.day)
WHERE earnings.earning_account_id = ?
ORDER BY day
where I'm assuming earning_account_id = ? is intended to be with a question mark because the language you're using to run the query is replacing it with the actual id before running the query.
SELECT
COALESCE(t1.amount,0) AS link_earnings,
COALESCE(t2.amount,0) AS publisher_referral_earnings,
COALESCE(t3.amount,0) AS advertiser_referral_earnings,
t1.day AS day
FROM
(
SELECT DATE_FORMAT(earning_created, '%c/%e/%Y') AS day, SUM(earning_amount) AS amount
FROM earnings
WHERE earning_referral_id = 0
AND (earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
AND earning_account_id = ?
GROUP BY DATE(earning_created)
) t1
LEFT JOIN
(
SELECT DATE_FORMAT(ep.earning_created, '%c/%e/%Y') AS day, (SUM(ep.earning_amount) * rp.referral_share) AS amount
FROM earnings AS ep
INNER JOIN referrals AS rp
ON ep.earning_referral_id = rp.referral_id
WHERE ep.earning_referral_id > 0
AND (ep.earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
AND ep.earning_account_id = ?
AND rp.referral_type = 0
GROUP BY DATE(ep.earning_created)
) t2
ON t1.day = t2.day
LEFT JOIN
(
SELECT DATE_FORMAT(ea.earning_created, '%c/%e/%Y') AS day, (SUM(ea.earning_amount) * ra.referral_share) AS amount
FROM earnings AS ea
INNER JOIN referrals AS ra
ON ea.earning_referral_id = ra.referral_id
WHERE ea.earning_referral_id > 0
AND (ea.earning_created > DATE_SUB(now(), INTERVAL 90 DAY))
AND ea.earning_account_id = ?
AND ra.referral_type = 1
GROUP BY DATE(ea.earning_created)
) t3
ON t1.day = t3.day
ORDER BY day
Seems to run ok....
You can simply use an outer join to retain earnings even when there is no matching referral, and then conditionally sum depending on whether a referral exists or not:
SELECT DATE_FORMAT(e.earning_created, '%c/%e/%Y') AS day,
SUM(IF(r.referral_id IS NULL, e.earning_amount, 0)) earning_standard,
SUM(IF(r.referral_id IS NULL, 0, e.earning_amount)) earning_referral
FROM earnings e LEFT JOIN referrals r ON r.referral_id = e.earning_referral_id
WHERE e.earning_account_id = ?
AND e.earning_created > CURRENT_DATE - INTERVAL 90 DAY
AND (r.referral_id IS NULL OR r.referral_type = 0)
GROUP BY 1
ORDER BY 1
I've assumed here that earnings.earning_referral_id is never negative, though you can add an explicit test to filter such records if so desired.
I've also changed the filter on earnings.earning_created to base from CURRENT_DATE rather than NOW() to ensure that any earnings created earlier than the current time on the first day of the series are still included—this would typically be what one actually wants, but feel free to change back if not.

MYSQL Current Year

I have a following SQL statement that should be returns the month, ph1, ph2 and ph3 values where minimum values of next month - minimum values of previous month
SELECT DATE_FORMAT(a1.date_time, '%M,%Y') AS month,
(a4.ph1_active_energy)*10 - a1.ph1_active_energy AS 'ph1', (a4.ph2_active_energy)*10 - a1.ph2_active_energy AS 'ph2', (a4.ph3_active_energy)*10 - a1.ph3_active_energy AS 'ph3'
FROM powerpro a1
JOIN (SELECT MONTH(date_time) month, MIN(date_time) AS min FROM powerpro GROUP BY MONTH(date_time)
) a2 ON a1.date_time = a2.min
JOIN (SELECT MONTH(date_time) month, MIN(date_time) AS min FROM powerpro GROUP BY DATE(date_time)
) a3 ON DATE(a1.date_time) = a3.date - INTERVAL 1 DAY
JOIN powerpro
a4 ON a4.date_time = a3.min
WHERE YEAR(a1.date_time) = YEAR(CURDATE()) ORDER BY a1.date_time
I want to get only the records of current year. But script returns the empty result set.
What may be going wrong. Can any one help me ?

Alternate mysql query for summing in subquery

I have a table that has the following fields:
date,amount,status
and I have a query that returns both the sum amount for each day (Quoted), as well as only the sum for a given status (SOLD).
It's very slow and I am trying to rewrite the query with no success.
The original query is:
SELECT
YEAR(FROM_UNIXTIME(date)) as Year,
lpad(MONTH(FROM_UNIXTIME(date)), 2, 0) as Month,
lpad(DAY(FROM_UNIXTIME(date)), 2, 0) as Day,
(SELECT
sum(amount)
FROM
mytable
where
status = 'SOLD'
and YEAR(FROM_UNIXTIME(date)) = Year
and lpad(MONTH(FROM_UNIXTIME(date)), 2, 0) = Month
and lpad(DAY(FROM_UNIXTIME(date)), 2, 0) = Day) as Sold,
(SELECT
sum(amount)
FROM
mytable
WHERE
YEAR(FROM_UNIXTIME(date)) = Year
and lpad(MONTH(FROM_UNIXTIME(date)), 2, 0) = Month
and lpad(DAY(FROM_UNIXTIME(date)), 2, 0) = Day) as Quoted
FROM
mytable
group by Year , Month , Day
The output looks like this (YYYY MM DD SUM):
2013 12 01 3442.00
Is there better way to write this so there it executes immediately? There are less than 10,000 records in the table.
You can at least avoid subqueries
SELECT
YEAR(FROM_UNIXTIME(date)) as Year,
lpad(MONTH(FROM_UNIXTIME(date)), 2, 0) as Month,
lpad(DAY(FROM_UNIXTIME(date)), 2, 0) as Day,
SUM(case
when status = 'SOLD' then amount
else 0 end) Sold,
sum(amount) as Quoted
from
mytable
GROUP BY Year , Month , Day

showing previous and current month data in table using mysql

I am trying to show three different figures of the same column In a mysql query, I would like to keep one month static: April, so it would be a case like this I want to show The current month, the previous month and the static month of the year I'm working with, in this case let us stick with 2012
Example
Tablename:payment
id , pay_date, amount
1 2012-02-12 1000
2 2012-03-11 780
3 2012-04-15 890
4 2012-05-12 1200
5 2012-06-12 1890
6 2012-07-12 1350
7 2012-08-12 1450
So what I want to do is show the column amount for the month of April as I said I want to keep that row static: 890, the current month lets say the current month is August:1450 and the previous month amount which would be July:1350: so the final result would be something like this:
april_amount current_month_amount previous_month_amount
890 1450 1350
However I'm stuck here:
select amount as april_amount
from payment
where monthname(pay_date) LIKE 'April'
and year(pay_date) LIKE 2012
I hope the question is written clear enough, and thanks alot for the help much appreciated.
If the results can be rows instead of columns:
SELECT MONTHNAME(pay_date), amount FROM payment
WHERE pay_date BETWEEN '2012-04-01'
AND '2012-04-30'
OR pay_date BETWEEN CURRENT_DATE
- INTERVAL DAYOFMONTH(CURRENT_DATE) - 1 DAY
AND LAST_DAY(CURRENT_DATE)
OR pay_date BETWEEN CURRENT_DATE
- INTERVAL DAYOFMONTH(CURRENT_DATE) - 1 DAY
- INTERVAL 1 MONTH
AND LAST_DAY(CURRENT_DATE - INTERVAL 1 MONTH)
See it on sqlfiddle.
I might be way off here. But try:
select top 1
p.amount, c.amount, n.amount
from payment c
inner join payment p ON p.pay_date < c.pay_date
inner join payment n ON n.pay_date > c.pay_date
where monthname(c.paydate) LIKE 'April'
and year(c.pay_date) LIKE 2012
order by p.pay_date DESC, n.pay_date ASC
EDIT, I didnt read your question properly. I was going for previous, current, and next month. 1 minute and I'll try again.
select top 1
p.amount AS april_amount, c.amount AS current_month_amount, n.amount AS previous_month_amount
from payment c
inner join payment p ON monthname(p.pay_date) = 'April' AND year(p.pay_date) = 2012
inner join payment n ON n.pay_date > c.pay_date
where monthname(c.paydate) = monthname(curdate())
and year(c.pay_date) = year(curdate())
order by n.pay_date ASC
This assumes there is only 1 entry per month.
Ok, so i haven't written in mysql for a while. here is what worked for your example data:
select
p.amount AS april_amount, c.amount AS current_month_amount, n.amount AS previous_month_amount
from payment AS c
inner join payment AS p ON monthname(p.pay_date) LIKE 'April' AND year(p.pay_date) LIKE 2012
inner join payment AS n ON n.pay_date < c.pay_date
where monthname(c.pay_date) LIKE monthname(curdate())
and year(c.pay_date) LIKE year(curdate())
order by n.pay_date DESC
limit 1
the previous month table joined is counterintuitively named n, but this works. I verified it in a WAMP install.
To handle aggregates per month you can use subselects. Performance may suffer on very large tables (millions of rows or more).
SELECT SUM( a.amount ) AS april_amount,
(
SELECT SUM( c.amount )
FROM payment c
WHERE MONTH( c.pay_date ) = MONTH( CURDATE( ) )
) AS current_month_amount,
(
SELECT SUM( p.amount )
FROM payment p
WHERE MONTH( p.pay_date ) = MONTH( CURDATE( ) - INTERVAL 1
MONTH )
) AS previous_month_amount
FROM payment a
WHERE MONTHNAME( a.pay_date ) = 'April'
AND YEAR( a.pay_date ) =2012