MySQL to get the count of rows that fall on a date for each day of a month - sql

I have a table that contains a list of community events with columns for the days the event starts and ends. If the end date is 0 then the event occurs only on the start day. I have a query that returns the number of events happening on any given day:
SELECT COUNT(*) FROM p_community e WHERE
(TO_DAYS(e.date_ends)=0 AND DATE(e.date_starts)=DATE('2009-05-13')) OR
(DATE('2009-05-13')>=DATE(e.date_starts) AND DATE('2009-05-13')<=DATE(e.date_ends))
I just sub in any date I want to test for "2009-05-13".
I need to be be able to fetch this data for every day in an entire month. I could just run the query against each day one at a time, but I'd rather run one query that can give me the entire month at once. Does anyone have any suggestions on how I might do that?
And no, I can't use a stored procedure.

Try:
SELECT COUNT(*), DATE(date) FROM table WHERE DATE(dtCreatedAt) >= DATE('2009-03-01') AND DATE(dtCreatedAt) <= DATE('2009-03-10') GROUP BY DATE(date);
This would get the amount for each day in may 2009.
UPDATED: Now works on a range of dates spanning months/years.

Unfortunately, MySQL lacks a way to generate a rowset of given number of rows.
You can create a helper table:
CREATE TABLE t_day (day INT NOT NULL PRIMARY KEY)
INSERT
INTO t_day (day)
VALUES (1),
(2),
…,
(31)
and use it in a JOIN:
SELECT day, COUNT(*)
FROM t_day
JOIN p_community e
ON day BETWEEN DATE(e.start) AND IF(DATE(e.end), DATE(e.end), DATE(e.start))
GROUP BY
day
Or you may use an ugly subquery:
SELECT day, COUNT(*)
FROM (
SELECT 1 AS day
UNION ALL
SELECT 2 AS day
…
UNION ALL
SELECT 31 AS day
) t_day
JOIN p_community e
ON day BETWEEN DATE(e.start) AND IF(DATE(e.end), DATE(e.end), DATE(e.start))
GROUP BY
day

Related

sql save row count of query every day

I want to create a view or table that counts eg. total number of students on that day the query is executed and add row results each day. Problem is the date column on table changes everyday to the current date.
SELECT
COUNT(*) AS no_of_Students
,CAST(GETDATE() AS DATE) as DATE
FROM mySchool
WHERE students=1
No of student . Date
-----------------------
8 . 2019.02.06
15 . 2019.02.07
(next row should auto update for next day when running the query)
You should not be using GETDATE(), You need to pick the date column you have in your mySchool table.
You need to write your query like following.
SELECT
COUNT(*) as [no_of_Students]
,CAST([DateCoulumn] AS DATE) as [DATE]
FROM [mySchool]
GROUP BY CAST(DateCoulumn AS DATE)
ORDER BY CAST(DateCoulumn AS DATE)
Note: You need to replace DateCoulumn with the correct column name.

Calculate clients per week based on start date and end date in MS Access

In a MS Access DB I have information about clients' arrival and departure dates. Based on this I would like to calculate the number of clients that will be visiting per week.
Consider the example below. Peter arrives in the first week of January and leaves on the third week (weeks start on Sunday). Mary on the other hand arrives and leaves in the first week.
I would like the output to be as shown below, with the week number in the first column and the total number of guests in the second.
What is the best way of achieving this please?
My solution with german date format, test with ORACLE. I build some calendar table (tw_test_week) for every week to join it.
CREATE TABLE tw_test_client (
client VARCHAR2(10),
arrival DATE,
departure DATE
);
INSERT INTO tw_test_client VALUES
( 'Peter', to_date('01.01.2018','DD.MM.YYYY'), to_date('11.01.2018','DD.MM.YYYY'));
INSERT INTO tw_test_client VALUES
( 'Mary', to_date('01.01.2018','DD.MM.YYYY'), to_date('01.02.2018','DD.MM.YYYY'));
CREATE TABLE tw_test_week (
weekid INT,
started DATE,
ended DATE
);
INSERT INTO tw_test_week VALUES
( to_char(to_date('01.01.2018','DD.MM.YYYY'),'WW'),
to_date('01.01.2018','DD.MM.YYYY'),
to_date('07.01.2018','DD.MM.YYYY')
);
INSERT INTO tw_test_week VALUES
( to_char(to_date('08.01.2018','DD.MM.YYYY'),'WW'),
to_date('08.01.2018','DD.MM.YYYY'),
to_date('14.01.2018','DD.MM.YYYY')
);
INSERT INTO tw_test_week VALUES
( to_char(to_date('15.01.2018','DD.MM.YYYY'),'WW'),
to_date('15.01.2018','DD.MM.YYYY'),
to_date('21.01.2018','DD.MM.YYYY')
);
INSERT INTO tw_test_week VALUES
( to_char(to_date('22.01.2018','DD.MM.YYYY'),'WW'),
to_date('22.01.2018','DD.MM.YYYY'),
to_date('28.01.2018','DD.MM.YYYY')
);
INSERT INTO tw_test_week VALUES
( to_char(to_date('29.01.2018','DD.MM.YYYY'),'WW'),
to_date('29.01.2018','DD.MM.YYYY'),
to_date('04.02.2018','DD.MM.YYYY')
);
SELECT w.weekid, COUNT(*)
FROM tw_test_week w
JOIN tw_test_client c
ON w.started BETWEEN c.arrival and c.departure
GROUP BY w.weekid
ORDER BY w.weekid;
Result
WEEKID COUNT
1 2
2 2
3 1
4 1
5 1
Create a table containing the numbers 1 to 53. This table in my query is called WeekNumTable and contains a single field with each week number listed.
SELECT WeekNum
, COUNT(WeekNum) AS TotalClients
FROM WeekNumTable INNER JOIN ClientTable ON
WeekNumTable.WeekNum>=DatePart("ww",ClientTable.Arrival-Weekday(ClientTable.Arrival,1)+7) AND
WeekNumTable.WeekNum<=DatePart("ww",ClientTable.Departure-Weekday(ClientTable.Departure,1)+7)
GROUP BY WeekNum
Your example confused me a little as you list week 3 as having 1 client, while the data table doesn't.
Edit: The one problem that I can see with this is that if you do want to look at the next 100 weeks you'll need something to separate the years otherwise week 1 from both years will be lumped together.
You can use a series of queries to obtain this.
First, create a query named Ten:
SELECT DISTINCT Abs([id] Mod 10) AS N
FROM MSysObjects;
Then you can create a query, ClientDays, that lists all your dates between first arrival and latest departure:
SELECT DISTINCT
[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100 AS Id,
DateAdd("d",[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100,[StartDate]) AS [Date]
FROM
Ten AS Ten_0,
Ten AS Ten_1,
Ten AS Ten_2,
(Select
Min([Arrival]) As StartDate,
DateDiff("d", Min([Arrival]), Max([Departure])) As Days
From
ClientDates) AS T
WHERE
((([Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100)<=[Days])
AND
((Ten_0.N)<=[Days]\1)
AND
((Ten_1.N)<=[Days]\10)
AND
((Ten_2.N)<=[Days]\100));
Use this in yet a query, ClientWeeks, to find the week numbers:
SELECT
Year([Date]) AS [Year],
DatePart("ww",[Date]) AS Week,
ClientDates.Client
FROM
ClientDays,
ClientDates
WHERE
ClientDays.Date Between [Arrival] And [Departure]
GROUP BY
Year([Date]),
DatePart("ww",[Date]),
ClientDates.Client;
Finally, count the clients:
SELECT
ClientWeeks.Year,
ClientWeeks.Week,
Count(ClientWeeks.Client) AS TotalClients
FROM
ClientWeeks
GROUP BY
ClientWeeks.Year,
ClientWeeks.Week;
Please note, that you will have trouble counting around New Year as you intend to use an inconsistent week numbering method.
The only week number that is unambiguous is the ISO-8601 system of yyyy-ww because the first and/or last week will cross the calendar year boundaries.
Leave a note if you wish to implement this as it cannot be done with native VBA functions; custom functions must be used, but I don't wish to post them here if you will not use them.

How to get all dates that they have at least one Event on that day from a given date range?

I am having a SQLite database which contains a table Events with start and end dates. I would like to get a Set (could be an array without duplicates) of dates that they at least have an Event on that day let's say from 1st of August to 20th of August.
Let's take some example events:
Event 1 from 02.08.2016 to 07.08.2016
Event 2 from 10.08.2016 to 12.08.2016
Event 3 from 11.08.2016 to 15.08.2016
Then the outcome should be:
[02.08.2016, 03.08.2016, 04.08.2016, 05.08.2016, 06.08.2016, 07.08.2016, 10.08.2016, 11.08.2016, 12.08.2016, 13.08.2016, 14.08.2016, 15.08.2016]
where 11.08.2016 and 12.08.2016 are not repeating.
NB: I am expecting an answer that could solve this problem only using SQL rather combining some programming code. I need that on a mobile device (iOS) where I am trying to optimize the user experience and performance.
Here is an example of creating a date table with recursive CTE and using it to select dates you need:
WITH RECURSIVE
cnt(dt) AS
(
SELECT MIN(startDate) FROM Events
UNION ALL
SELECT date(dt,'+1 day') FROM cnt
WHERE dt < (SELECT MAX(endDate) FROM Events)
LIMIT 10000
)
SELECT DISTINCT dt
FROM cnt
JOIN Events ON dt BETWEEN startDate AND endDate
ORDER BY dt;
SQL fiddle demo

SELECT statement optimization

I'm not so expert in SQL queryes, but not even a complete newbie.
I'm exporting data from a MS-SQL database to an excel file using a SQL query.
I'm exporting many columns and two of this columns contain a date and an hour, this are the columns I use for the WHERE clause.
In detail I have about 200 rows for each day, everyone with a different hour, for many days. I need to extract the first value after the 15:00 of each day for more days.
Since the hours are different for each day i can't specify something like
SELECT a,b,hour,day FROM table WHERE hour='15:01'
because sometimes the value is at 15:01, sometimes 15:03 and so on (i'm looking for the closest value after the 15:00), for fix this i used this workaround:
SELECT TOP 1 a,b,hour,day FROM table WHERE hour > "15:00"
in this way i can take the first value after the 15:00 for a day...the problem is that i need this for more days...for a user-specifyed interval of days. At the moment i fix this with a UNION ALL statement, like this:
SELECT TOP 1 a,b,hour,day FROM table WHERE data="first_day" AND hour > "15:00"
UNION ALL SELECT TOP 1 a,b,hour,day FROM table WHERE data="second_day" AND hour > "15:00"
UNION ALL SELECT TOP 1 a,b,hour,day FROM table WHERE data="third_day" AND hour > "15:00"
...and so on for all the days (i build the SQL string with a for each day in the specifyed interval).
Until now this worked, but now I need to expand the days interval (now is maximun a week, so 5 days) to up to 60 days. I don't want to build an huge query string, but i can't imagine an alternative way for write the SQL.
Any help appreciated
Ettore
I typical solution for this uses row_number():
SELECT a, b, hour, day
FROM (SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY day ORDER BY hour) as seqnum
FROM table t
WHERE hour > '15:00'
) t
WHERE seqnum = 1;

Display a rolling 12 weeks chart in SSRS report

I am calling the data query in ssrs like this:
SELECT * FROM [DATABASE].[dbo].[mytable]
So, the current week is the last week from the query (e.g. 3/31 - 4/4) and each number represents the week before until we have reached the 12 weeks prior to this week and display in a point chart.
How can I accomplish grouping all the visits for all locations by weeks and adding it to the chart?
I suggest updating your SQL query to Group by a descending Dense_Rank of DatePart(Week,ARRIVED_DATE). In this example, I have one column for Visits because I couldn't tell which columns you were using to get your Visit count:
-- load some test data
if object_id('tempdb..#MyTable') is not null
drop table #MyTable
create table #MyTable(ARRIVED_DATE datetime,Visits int)
while (select count(*) from #MyTable) < 1000
begin
insert into #MyTable values
(dateadd(day,round(rand()*100,0),'2014-01-01'),round(rand()*1000,0))
end
-- Sum Visits by WeekNumber relative to today's WeekNumber
select
dense_rank() over(order by datepart(week,ARRIVED_DATE) desc) [Week],
sum(Visits) Visits
from #MyTable
where datepart(week,ARRIVED_DATE) >= datepart(week,getdate()) - 11
group by datepart(week,ARRIVED_DATE)
order by datepart(week,ARRIVED_DATE)
Let me know if I can provide any more detail to help you out.
You are going to want to do the grouping of the visits within SQL. You should be able to add a calculated column to your table which is something like WorkWeek and it should be calculated on the days difference from a certain day such as Sunday. This column will then by your X value rather than the date field you were using.
Here is a good article that goes into first day of week: First Day of Week