Alternate mysql query for summing in subquery - mysql

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

Related

MySQL get different SUMs based on dates

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

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 if data no exist for in order dates

SELECT
EXTRACT( DAY FROM date) AS day,
EXTRACT( MONTH FROM date) AS month, who, sum ( wsd ) AS total FROM weekly
WHERE season = '08'
AND status = 1
AND who = 'NAME SURNAME'
GROUP BY day, month
day month who total
12 8 NAME SURNAME 18
I am getting totals of "wsd" column for every person in "who" column per day. If one person doesn't have records in table for a day, we can not see that name in the results as expected.
But i want to see that records too, with date and name with "0" in total column.
How can i do it with mysql only?
For this case, you can move the conditional logic from the where to the aggregation -- assuming that you have data for someone on every day:
SELECT EXTRACT( DAY FROM date) AS day, EXTRACT( MONTH FROM date) AS month, who,
sum(case when status = 1 AND who = 'NAME SURNAME' then wsd else 0 end) AS total
FROM weekly
WHERE season = '08'
GROUP BY day, month;
Did you try Coalesce or Isnull for inserting default values(in your case 0) ?

How to count consecutive number of 10 days

I have table with columns: id, name, date, present
Column present have values 0 or 1 or 2 and ... more
I need to count how many 0 valous is in current month 2013-07-01 - 2013-07-31 but count only when there are or more than 10 times.
for example if i have
2013-07-01 to 2013-07-10 valoues 0 it should count it and let me know that is 10 or more consecutives days like 11, 12 or more, but if it was less than 10 should count nothing.
I was trying some examples from stack... but they are different problems... so i need little help with that mysql query.
i have smth like this but need consecutives 10 days like >= 10
$sql = mysql_query("SELECT COUNT(name) as count FROM `table` WHERE (`present` = 0) AND (`date` BETWEEN '2013-07-01' AND '2013-07-31')");
while($row = mysql_fetch_array($sql)){
$result = $row['count'];
}
It counts me every 0 values in date between 2013-07-01 and 2013-07-31 but i need count how many days start from 10 or more consecutives days
column present have 0 and other numbers like 1, 2, 3... so i need count only 0 with 10 or more consecutives days
here is SqlFiddle i was trying to make warking from answer
http://sqlfiddle.com/#!2/1bde8/2
best regards
m.
This approach uses correlated subqueries to calculate two values.
The first value is the date of the previous record where Present = 1. This allows you to get the number of days in a row where Present = 0 by using datediff().
The second is the Present value of tomorrow, which will be NULL on the last day of the month. When today has Present = 0 and tomorrow is either 1 or NULL, then we can use this record. It is the end of a sequence of 0s.
From there is it just a question of adding up the values according to the conditions that you set. The following query assumes that you want to do this for each name:
select name, sum(case when datediff(date, lastPresentDate) >= 10
then datediff(date, lastPresentDate)
else 0 end) as DaysCounted
from (select t.*,
(select coalesce(max(date), '2013-06-30')
from t t2
where t2.name = t.name and
t2.present <> 0 and
t2.date <= t.date and
t2.date between '2013-07-01' and '2013-07-31'
) as lastPresentDate,
(select t2.present
from t t2
where t2.name = t.name and
t2.date = adddate(t.date, 1)
order by t2.date
limit 1
) as TomorrowPresent
from t
where date between '2013-07-01' and '2013-07-31'
) t
where Present = 0 and (TomorrowPresent = 1 and TomorrowPresent is null)
group by name
This query should give you a count only when it is 10 or greater than 10.
SELECT COUNT(`name`) as `count`
FROM `table`
WHERE (`present` = 0)
AND (`date` BETWEEN '2013-07-01' AND '2013-07-31')
HAVING `count` >= 10;
Hope it helps!
Not tested, but you could use user variables like this:-
SELECT SUM(if(ConsCounter=10, 1, 0))
FROM
(
SELECT id, name, date, present, #Counter := IF(#PrevPresent = present AND present = 0, #Counter + 1, 0) AS ConsCounter, #PrevPresent = present
FROM
(
SELECT id, name, date, present
FROM `table`
ORDER BY date
) Sub1
CROSS JOIN (SELECT #PrevPresent:=-99999, #Counter:=0) Sub2
) Sub4
Get all the records in date order and add a sequence number for the count since the present was first 0. Then count the number of times that counter is 10.

MySQL SUM IF field b = field a

SELECT
incMonth as Month,
SUM( IF(item_type IN('typ1', 'typ2') AND incMonth = Month, 1, 0 ) )AS 'Total Sales'
FROM tester
I just need the sum for the current month its looping through.
If I'm reading that right, you'd need to use a group-by or at least a where clause to restrict things to just the time range you're wanting:
SELECT incMonth AS Month, SUM(IF(item_type IN('typ1', 'typ2'), 1, 0)) AS 'Total Sales'
FROM tester
GROUP BY incMonth