I have the following query to get the monthly amount of users:
SELECT count(user_id) from subs
where (started_at between #start_date and #start_date + interval 1 month
or (expires_at>#start_date + interval 1 month and started_at<#start_date))
If we had the following DB:
user_id started_at expires_at
=============================
1 2015-01-01 2015-12-31
2 2015-01-01 2015-01-03
3 2015-02-01 2015-02-28
4 2015-03-01 2015-03-31
5 2015-04-01 2015-04-31
6 2015-04-01 2016-04-01
7 2015-05-01 2015-05-09
I need a query that will return the following table:
2015-01 - 2
2015-02 - 2 (because one of Jan records doesn't expire till Dec)
2015-03 - 2
2015-04 - 3
2015-05 - 3
etc
So what is the efficient way to get this result in one query?
You probably want something like this:
SELECT YEAR(started_at) as 'Year',
MONTH(started_at) as 'Month',
COUNT(user_id) as 'Users'
FROM subs
GROUP BY YEAR(started_at),MONTH(started_at);
Note that in case a month has no users, this query will not return an entry for that month. If you want to also include months with 0 users you want a more complex query; check this for more info.
You want to GROUP BY the year and month.
Assuming your started_at column is of a DATE type, you can f.e. use GROUP_BY YEAR(started_at), MONTH(started_at), or also use DATE_FORMAT to format the column value to a single string value, of the form YYYY-MM and GROUP BY that. Select that same value as a column too, to get the proper identifier you want.
Related
update: this can be done with python. here
i have a table like this:
event_id vendor_id start_date end_date
1 100 2021-01-01 2021-01-31
2 101 2021-01-15 2021-02-15
3 102 2021-02-01 2021-02-31
4 103 2021-02-01 2021-03-31
5 104 2021-03-01 2021-03-31
6 105 2021-03-01 2021-04-31
7 100 2021-04-01 2021-04-31
i would like an output like this: number of events based on month. but if the event between two or more months, it must be included in the count for each month. For example, The event in the second row (event_id=2) takes place in both January and February. Therefore, this event should be included in the total both in January and February.
output:
month total_event
2021-01 2 ---->> event_id=(1,2)
2021-02 3 ---->> event_id=(2,3,4)
2021-03 3 ---->> event_id=(4,5,6)
2021-04 2 ---->> event_id=(6,7)
Note: I wrote it to make the " --->> event_id= : " part better understood. i dont needed. i just need the month and the total_event.
i tried this query:
select date_format(start_date,'%Y-%m') as month,count(event_id) as total_event
group by date_format(start_date,'%Y-%m')
month total_event
2021-01 2
2021-02 2
2021-03 2
2021-04 1
but it counts only by start_date, so the numbers are missing.
Idea
To get the valid months list from the table
To calculate the event counts by event table's joining with the months
MySQL 8.0+
We can get the valid months list by Recursive.
Here is a full SQL. Assumed that your event table is c!
WITH RECURSIVE all_dates(dt) AS (
-- anchor
SELECT MIN(c.`start_date`) AS dt FROM c
UNION ALL
-- recursion with stop condition
SELECT dt + INTERVAL 1 MONTH
FROM all_dates WHERE dt + INTERVAL 1 MONTH <= (SELECT MAX(c.end_date) FROM c)
)
SELECT LEFT(dt, 7) AS `month`, COUNT(d.dt) AS total_event, GROUP_CONCAT(DISTINCT c.`event_id`) AS event_ids FROM all_dates d
INNER JOIN c ON LEFT(d.dt, 7) >= LEFT(c.start_date, 7) AND LEFT(d.dt, 7) <= LEFT(c.end_date, 7)
GROUP BY LEFT(dt, 7);
I have two tables
Table_1 : Routes_Day_plan
Date Status_Id
------------------------
2019-06-09 1
2019-06-10 2
2019-06-09 2
2019-06-11 3
2019-06-14 4
2019-06-14 6
2019-06-15 8
Table_2 : Codes
id code
-------
1 Leave
2 Half_leave
3 Holiday
4 Work
5 Full_Hours
Now my task is to count week wise from table 1 where code (from second table) = Leave,Half_leave,work and than also show the sum , and where date not found show 0 , i write this query it's return data but not empty dates can someone please help ,
My Query:
select COUNT(*) as available, DATE(date)
from Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
group by date
UNION ALL
SELECT COUNT(date), 'SUM' date
FROM Table_1
where status_id in (
select id from codes
where code in ('Leave','Half_leave','work'))
AND DATE(date) >= DATE('2019-06-09') AND DATE(date) <= DATE('2019-06-16')
Result Something Like ,
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
2 2019-06-14
2 2019-06-15
17 SUM
I want like this
available Dates
------------------------
5 2019-06-09
2 2019-06-10
3 2019-06-11
3 2019-06-12
0 2019-06-13
2 2019-06-14
2 2019-06-15
17 SUM
Your best bet here would be to have a Date Dimension/Lookup table which contains pre-populated dates for the entire year. By joining your record table to this lookup, you essentially allocate your data to each date that actually exist (ex. 2019-06-13) and if your data is not found in the lookup, you will find a null in that field.
The Count function will count a null as a 0. Just make sure you group on the date field from your lookup table and not from your record table.
Make a table, a date dimension that contains all the dates value, from beginning to end. Like this:
Set EndDate = '2099-01-01';
Set RunDate = '1900-01-01';
WHILE RunDate <= EndDate DO
insert into dim_date
(`DATE`)
select
RunDate as DATE
;
Set RunDate = ADDDATE(RunDate,1);
END WHILE;
Create temporary table with dim_date left join Routes_Day_plan and set Status as 0 maybe for record that dont match. Use this temporary table then instead of Routes_Day_plan in your queries.
I have table as following:
hours | ... | task_assigned | task_deadline | task_completion
----------------------------------------------------------------
123 | ... | 2019-08-01 | - | -
234 | ... | - | 2018-08-01 | 2019-08-01
145 | ... | 2017-08-01 | 2017-08-01 | 2018-01-01
I want to calculate total hours for each year, i.e. grouping by year.
Currently I'm only taking into account task_completion field.
If there's no value in task_completion field, the record is not included in SUM calculation.
To elaborate further, say for year 2019, row 1 and 1 both should be considered. Hence the total hours should be 123 + 234 = 357.
And for year 2018, row 2 and 3.
Similarly, for year 2017, row 3.
SELECT YEAR(task_completion) as year, ROUND(SUM(total_hours), 2) as hours
FROM task
GROUP BY year
HAVING year BETWEEN '$year_from' AND '$year_to'
The resultset:
year | hours
--------------------
2017 | <somevalue>
2018 | <somevalue>
2019 | <somevalue>
How can I include other two date fields too?
You want to consider each row once for each of its years. Use UNION to get these years:
select year, round(sum(total_hours), 2) as hours
from
(
select year(task_assigned) as year, total_hours from task
union
select year(task_deadline) as year, total_hours from task
union
select year(task_completion) as year, total_hours from task
) years_and_hours
group by year
having year between $year_from and $year_to
order by year;
If you want to consider a row with one year twice or thrice also as often in the sum, then change UNION to UNION ALL.
Basically, you want to unpivot the data. I will assume that the - represents a NULL value and your dates are real dates.
select year(dte) as year, sum(total_hours) as hours
from ((select task_assigned as dte, total_hours
from task
) union all
(select task_deadline, total_hours
from task
) union all
(select task_completion, total_hours
from task
)
) d
where dte is not null
group by year(dte)
order by year(dte);
Based on your sample data, the round() is not necessary so I removed it.
If you want to filter for particular years, the filtering should be in a where clause -- so it filters the data before aggregation.
Change the where to:
where year(dte) >= ? and year(dte) <= ?
or:
where dte >= ? and dte <= ?
to pass in the dates.
The ? are for parameter placeholders. Learn how to use parameters rather than munging query strings.
This answer is no langer valid with the updated request.
If I understand correctly, you want to use task_assigned if the task_completion is still null. Use COALEASCE for this.
SELECT
YEAR(COALESCE(task_completion, task_assigned)) as year,
ROUND(SUM(total_hours), 2) as hours
FROM task
GROUP BY year
HAVING year BETWEEN $year_from AND $year_to
ORDER BY year;
(I don't think you actually want to use task_deadline, too, for how could a task get completed before getting assigned first? If such can occur, then include it in the COALESCE expression. Probably: COALESCE(task_completion, task_assigned, task_deadline)` then.)
Having this simple log table
id |val |dt
-------------------------
A 100 2014-01-15 00:00:00
A 160 2014-01-15 00:00:00
A 100 2014-01-15 01:00:00
A 160 2014-01-15 02:00:00
A 200 2014-01-15 03:00:00
A 80 2014-01-16 01:00:00
B 100 2014-01-16 02:00:00
B 200 2014-01-16 01:00:00
B 100 2014-01-15 02:00:00
and so on...
I can average a SINGLE day(15), of a SINGLE given id (A), in a specified range (0-2) by doing this
select id,
date(dt),
AVG(val) as av
from (SELECT id, val, dt
FROM test
WHERE id = 'A' AND
(date(dt) BETWEEN '2014-01-15' AND '2014-01-15') AND
( (time(dt) BETWEEN '00:00' AND '02:00'))) as outerTable
I get this SINGLE result
id |date | average 00:00 to 2:00
-------------------------
A 2014-01-15 120.0000
But how to solve that average of MULTIPLE days in same time period, but in many days in range of months? years? like
id |date | average 00:00 to 2:00
-------------------------
A 2014-01-15 120.0000
A 2014-01-16 80.0000
A 2014-01-17 35.0000
and so on...
Need of loop the same query on different days for the whole month or year, of course the literal loop can be done in php, but it is SLOW, Also I could loop for every ID, making it slower.
You do not need to use Subquery, to get the data and then calculate the average in the Outer query. It can be done without the subquery itself.
In order to get the average value for different dates, you can remove the WHERE condition on date, to get the data for all the date(s). You can also change the WHERE condition on date to include a range instead.
You also seem to want results for different id values. We can get rid of WHERE condition on id as well.
Eventually, you can do a GROUP BY on the id and date, to get individual rows idwise, and then datewise.
SELECT
id,
DATE(dt)
AVG(val)
FROM test
WHERE
TIME(dt) BETWEEN '00:00' AND '02:00'
GROUP BY id, DATE(dt)
I have a table like this:
id | created_on
1 2013-09-03 20:05:09
2 2013-09-05 17:03:13
...
How do I write a query to return a result of record counts that was created from Date X to Date Y in 7-day intervals?
So the result would look like this:
count | created_on
4 2013-09-17 00:00:00
2 2013-09-24 00:00:00
1 2013-09-31 00:00:00
10 2013-10-07 00:00:00
...
You can go to the beginning of the week by subtracting the day of the week. Here is one way to do that:
select date(created_on - interval dayofweek(created_on) day), count(*)
from t
group by date(created_on - interval dayofweek(created_on) day);
If this is not the day you want the week to start, then you can add an offset day.
Group by the date field, floored to the week:
SELECT
count(*),
YEARWEEK(created_on) as week
FROM
yourtable
GROUP BY week
This assumes that created_on is a type that can be interpreted as a date:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_yearweek
This will get you weekly groupings, but you may want to then convert that field (which will look like YYYYWW) back to something more readable.
You can try this
SELECT created_on, count( id ) AS count
FROM `test_table`
WHERE created_on
BETWEEN '2013-09-01'
AND '2013-10-10'
GROUP BY WEEK( created_on )