Counting the # of days in each month, subsequent of a date - sql

I'm trying to see if I can calculate the # of days in each month, after a given date for a certain # of days.
For example, I have a date of 2019-09-25. If I am planning for the next 105 days, how many of those days are in September, October, November, and so on?
Declare #dtdate date = '20190925',
#days int= 105
Select
datediff(dd,#dtdate,eomonth(#dtdate)) as DaysSeptember
,datediff(dd,eomonth(#dtdate),eomonth(dateadd(m,1,#dtdate))) as DaysOctober

It looks to me like Sql server. You can do it by simply counting days in each month. Doing it this way has an advantage of flexibility. You can simply change #dtdate, #days and the query will work despite of changing number of months.
DECLARE #dtdate date = '20190925',
#days int= 105
,#dtmax date;
set #dtmax = dateadd(day, #days, #dtdate);
WITH cte AS (
SELECT DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY 1/0), #dtdate) AS d
FROM sys.objects s, sys.objects s2
)
select
year(d) as year, datename(month, d) as month, count(*) as NumberOfDays
from cte
where d between #dtdate and #dtmax
group by year(d), datename(month, d)
order by year(d), month
result:
year month NumberOfDays
2019 December 31
2019 November 30
2019 October 31
2019 September 5
2020 January 8

In postgresql I'd do this by
SELECT date_part('month', d), count(d)
FROM generate_series('2019-09-25'::date, '2019-09-25'::date + INTERVAL '105 days', INTERVAL '1 day') series (d)
GROUP BY date_part('year',d), date_part('month', d)
ORDER BY date_part('year',d), date_part('month', d)
Clearly you're not using postgresql but perhaps this will give you a hint. The trick is to create a series of dates within the interval that you can then count. Here'st the output with the month and number of days. Note there are 106 days because the interval is inclusive of the beginning and end dates.
9;6
10;31
11;30
12;31
1;8

Perhaps not the best solution (not set based), but an alternative approach:
DECLARE #dtdate DATE = '20190925'
,#days INT = 105
,#DaysInMonth INT
DECLARE #results TABLE
(
ResultsID INT NOT NULL IDENTITY PRIMARY KEY
,YearMonth VARCHAR(7) NOT NULL
,DaysInMonth INT NOT NULL
)
WHILE #days > 0
BEGIN
SET #DaysInMonth = DATEDIFF(dd, #dtdate, EOMONTH(#dtdate))
SET #DaysInMonth = IIF(#days > #DaysInMonth, #DaysInMonth, #days)
INSERT INTO #results
(
YearMonth
,DaysInMonth
)
SELECT CONVERT(VARCHAR(7), #dtdate, 120)
,#DaysInMonth
SET #days -= #DaysInMonth
SET #dtdate = DATEADD(dd, 1, EOMONTH(#dtdate))
END
SELECT *
FROM #results AS r

Related

If/Then/Else in Formatting a Date

I am trying to get the fiscal period and year out of an invoice date. Using the month() function together with the Case I am able to get the period. since Period 1 is in November I need to do a +1 1 the year when this is true
Using the IF function together with the date functions are now working for me.
My query is
Select a.OrderAccount
,a.InvoiceAccount
,a.InvoiceDate
,year(a.InvoiceDate) as Year
,month(a.InvoiceDate) as Month,
Case month(a.InvoiceDate)
WHEN '11' THEN '1' -- increase year by +1
WHEN '12' THEN '2'-- increase year by +1
WHEN '1' THEN '3'
WHEN '2' THEN '4'
WHEN '3' THEN '5'
Any advice would be appreciated. Thanks
Use DATEADD to just add 2 months to the original date:
MONTH(DATEADD(month,2,a.InvoiceDate)) as FiscalMonth,
YEAR(DATEADD(month,2,a.InvoiceDate)) AS FiscalYear,
Create and populate a Calendar Table (it makes working with dates much easier).
create table Calendar
(
id int primary key identity,
[date] datetime,
[day] as datepart(day, [date]) persisted,
[month] as datepart(month, [date]) persisted,
[year] as datepart(year, [date]) persisted,
day_of_year as datepart(dayofyear, [date]) persisted,
[week] as datepart(week, [date]),
day_name as datename(dw, [date]),
is_weekend as case when datepart(dw, [date]) = 7 or datepart(dw, [date]) = 1 then 1 else 0 end,
[quarter] as datepart(quarter, [date]) persisted
--etc...
)
--populate the calendar
declare #date datetime
set #date = '1-1-2000'
while #date <= '12-31-2100'
begin
insert Calendar select #date
set #date = dateadd(day, 1, #date)
end
Then, create a FiscalYear view:
create view FiscalYear
as
select
id,
case when month = 11 or month = 12 then year + 1 else year end as [year]
from Calendar
So, whenever you need the fiscal year of a given date, just use something like the following query:
select C.*, FY.year fiscal_year from Calendar C inner join FiscalYear FY on FY.id = C.id
Of course, since fiscal year is just a computation on a column, you could also just make it a part of the calendar table itself. Then, it's simply:
select * from Calendar
If you want to stick with arithmetic: The fiscal month is ( Month( a.InvoiceDate ) + 1 ) % 12 + 1 and the value to add to the calendar year to get the fiscal year is Month( a.InvoiceDate ) / 11.
The following code demonstrates 12 months:
with Months as (
select 1 as M
union all
select M + 1
from Months
where M < 12 )
select M, ( M + 1 ) % 12 + 1 as FM, M / 11 as FYOffset
from Months;
D Stanley's answer makes your intention clearer, always a consideration for maintainability.
If you have this logic in 10 different places and the logic changes starting (say) on 1/1/2018 you will have a mess on your hands.
Create a function that has the logic and then use the function like:
SELECT InvoiceDate, dbo.FiscalPeriod(InvoiceDate) AS FP
FROM ...
Something like:
CREATE FUNCTION dbo.FiscalPeriod(#InvoiceDate DateTime)
RETURNS int
AS BEGIN
DECLARE #FiscalDate DateTime
SET #FiscalDate = DATEADD(month, 2, #InvoiceDate)
RETURN YEAR(#FiscalDate) * 100 + MONTH(#FiscalDate)
END
This returns values like 201705, but you could have dbo.FiscalPeriodMonth() and dbo.FiscalPeriodYear() if you needed. And you can have as complicated logic as you need in one place.

Calculate number Hours from Date range excluding weekend dates in sql

I have a range of date i.e start date 19/05/2017 till end date 25/05/2017. I want to get the hours calculated in between them without including weekends i.e friday and saturday.
For example:
7 days have 7*24= 168 hrs
5 days excluding friday and Saturday will give 120hrs.
Any function that can be used in another query?
create function dbo.GetHoursWithoutWeekends (#date1 date, #date2 date)
returns int
as
begin
declare #hours int
set #hours = 24 * (DATEDIFF(day, #date1, #date2) + 1 - (
select
count(DATEADD(day, t.Rbr - 1, #date1)) as WeekEndCount
from (
select
ROW_NUMBER() over (order by sc1.name) as Rbr
from sys.syscolumns sc1
cross join sys.syscolumns sc2
) t
where DATEADD(day, t.Rbr - 1, #date1) between #date1 and #date2
and DATEPART(weekday, DATEADD(day, t.Rbr - 1, #date1)) in (5, 6)
));
return #hours;
end
GO
set datefirst 1
select dbo.GetHoursWithoutWeekends ('20170519', '20170525')

t-sql select get all Months within a range of years

I need a select to return Month and year Within a specified date range where I would input the start year and month and the select would return month and year from the date I input till today.
I know I can do this in a loop but I was wondering if it is possible to do this in a series selects?
Year Month
---- -----
2010 1
2010 2
2010 3
2010 4
2010 5
2010 6
2010 7
and so on.
Gosh folks... using a "counting recursive CTE" or "rCTE" is as bad or worse than using a loop. Please see the following article for why I say that.
http://www.sqlservercentral.com/articles/T-SQL/74118/
Here's one way to do it without any RBAR including the "hidden RBAR" of a counting rCTE.
--===== Declare and preset some obviously named variables
DECLARE #StartDate DATETIME,
#EndDate DATETIME
;
SELECT #StartDate = '2010-01-14', --We'll get the month for both of these
#EndDate = '2020-12-05' --dates and everything in between
;
WITH
cteDates AS
(--==== Creates a "Tally Table" structure for months to add to start date
-- calulated by the difference in months between the start and end date.
-- Then adds those numbers to the start of the month of the start date.
SELECT TOP (DATEDIFF(mm,#StartDate,#EndDate) + 1)
MonthDate = DATEADD(mm,DATEDIFF(mm,0,#StartDate)
+ (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1),0)
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2
)
--===== Slice each "whole month" date into the desired display values.
SELECT [Year] = YEAR(MonthDate),
[Month] = MONTH(MonthDate)
FROM cteDates
;
I know this is an old question, but I'm mildly horrified at the complexity of some of the answers. Using a CTE is definitely the simplest way to go for selecting these values:
WITH months(dt) AS
(SELECT getdate() dt
UNION ALL
SELECT dateadd(month, -1, dt)
FROM months)
SELECT
top (datediff(month, '2017-07-01' /* start date */, getdate()) + 1)
YEAR(months.dt) yr, MONTH(months.dt) mnth
FROM months
OPTION (maxrecursion 0);
Just slap in whichever start date you'd like in place of the '2017-07-01' above and you're good to go with an efficient and easily-integrated solution.
Edit: Jeff Moden's answer quite effectively advocates against using rCTEs. However, in this case it appears to be a case of premature optimization - we're talking about 10's of records in all likelihood, and even if you span back to 1900 from today, it's still a minuscule hit. Using rCTEs to achieve code maintainability seems to be worth the trade if the expected result set is small.
You can use something like this: Link
To generate the equivalent of a numbers table using date ranges.
But could you please clarify your inputs and outputs?
Do you want to input a start date, for example, '2010-5-1' and end date, for example, '2010-8-1' and have it return every month between the two? Do you want to include the start month and end month, or exclude them?
Here's some code that I wrote that will quickly generate an inclusive result of every month between two dates.
--Inputs here:
DECLARE #StartDate datetime;
DECLARE #EndDate datetime;
SET #StartDate = '2010-1-5 5:00PM';
SET #EndDate = GETDATE();
--Procedure here:
WITH RecursiveRowGenerator (Row#, Iteration) AS (
SELECT 1, 1
UNION ALL
SELECT Row# + Iteration, Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1))
UNION ALL
SELECT Row# + (Iteration * 2), Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1))
)
, SqrtNRows AS (
SELECT *
FROM RecursiveRowGenerator
UNION ALL
SELECT 0, 0
)
SELECT TOP(DATEDIFF(MONTH, #StartDate, #EndDate)+1)
DATEADD(month, DATEDIFF(month, 0, #StartDate) + A.Row# * POWER(2,CEILING(LOG(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1))/LOG(2))) + B.Row#, 0) Row#
FROM SqrtNRows A, SqrtNRows B
ORDER BY A.Row#, B.Row#;
Code below generates the values for the range between 21 Jul 2013 and 15 Jan 2014.
I usually use it in SSRS reports for generating lookup values for the Month parameter.
declare
#from date = '20130721',
#to date = '20140115';
with m as (
select * from (values ('Jan', '01'), ('Feb', '02'),('Mar', '03'),('Apr', '04'),('May', '05'),('Jun', '06'),('Jul', '07'),('Aug', '08'),('Sep', '09'),('Oct', '10'),('Nov', '11'),('Dec', '12')) as t(v, c)),
y as (select cast(YEAR(getdate()) as nvarchar(4)) [v] union all select cast(YEAR(getdate())-1 as nvarchar(4)))
select m.v + ' ' + y.v [value_field], y.v + m.c [label_field]
from m
cross join y
where y.v + m.c between left(convert(nvarchar, #from, 112),6) and left(convert(nvarchar, #to, 112),6)
order by y.v + m.c desc
Results:
value_field label_field
---------------------------
Jan 2014 201401
Dec 2013 201312
Nov 2013 201311
Oct 2013 201310
Sep 2013 201309
Aug 2013 201308
Jul 2013 201307
you can do the following
SELECT DISTINCT YEAR(myDate) as [Year], MONTH(myDate) as [Month]
FROM myTable
WHERE <<appropriate criteria>>
ORDER BY [Year], [Month]
---Here is a version that gets the month end dates typically used for accounting purposes
DECLARE #StartDate datetime;
DECLARE #EndDate datetime;
SET #StartDate = '2010-1-1';
SET #EndDate = '2020-12-31';
--Procedure here:
WITH RecursiveRowGenerator (Row#, Iteration)
AS ( SELECT 1, 1
UNION ALL
SELECT Row# + Iteration, Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1))
UNION ALL SELECT Row# + (Iteration * 2), Iteration * 2
FROM RecursiveRowGenerator
WHERE Iteration * 2 < CEILING(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1)) )
, SqrtNRows AS ( SELECT * FROM RecursiveRowGenerator
UNION ALL SELECT 0, 0 )
SELECT TOP(DATEDIFF(MONTH, #StartDate, #EndDate)+1)
DateAdd(d,-1,DateAdd(m,1, DATEADD(month, DATEDIFF(month, 0, #StartDate) + A.Row# * POWER(2,CEILING(LOG(SQRT(DATEDIFF(MONTH, #StartDate, #EndDate)+1))/LOG(2))) + B.Row#, 0) ))
Row# FROM SqrtNRows A, SqrtNRows B ORDER BY A.Row#, B.Row#;
DECLARE #Date1 DATE
DECLARE #Date2 DATE
SET #Date1 = '20130401'
SET #Date2 = DATEADD(MONTH, 83, #Date1)
SELECT DATENAME(MONTH, #Date1) "Month", MONTH(#Date1) "Month Number", YEAR(#Date1) "Year"
INTO #Month
WHILE (#Date1 < #Date2)
BEGIN
SET #Date1 = DATEADD(MONTH, 1, #Date1)
INSERT INTO #Month
SELECT DATENAME(MONTH, #Date1) "Month", MONTH(#Date1) "Month Number", YEAR(#Date1) "Year"
END
SELECT * FROM #Month
ORDER BY [Year], [Month Number]
DROP TABLE #Month
declare #date1 datetime,
#date2 datetime,
#date datetime,
#month integer,
#nm_bulan varchar(20)
create table #month_tmp
( bulan integer null, keterangan varchar(20) null )
select #date1 = '2000-01-01',
#date2 = '2000-12-31'
select #month = month(#date1)
while (#month < 13)
Begin
IF #month = 1
Begin
SELECT #date = CAST( CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,0,#date1))-1),DATEADD(mm,0,#date1)),111) + ' 00:00:00' as DATETIME )
End
ELSE
Begin
SELECT #date = CAST( CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,#month -1,#date1))-1),DATEADD(mm,#month -1,#date1)),111) + ' 00:00:00' as DATETIME )
End
select #nm_bulan = DATENAME(MM, #date)
insert into #month_tmp
select #month as nilai, #nm_bulan as nama
select #month = #month + 1
End
select * from #month_tmp
drop table #month_tmp
go

Calculating in SQL the first working day of a given month

I have to calculate all the invoices which have been paid in the first 'N' days of a month. I have two tables
. INVOICE: it has the invoice information. The only field which does matter is called 'datePayment'
. HOLYDAYS: It is a one column table. Entries at this table are of the form "2009-01-01",
2009-05-01" and so on.
I should consider also Saturdays and Sundays
(this might be not a problem because I could insert those days at the Hollidays table in order to consider them as hollidays if neccesary)
The problem is to calculate which is the 'payment limit'.
select count(*) from invoice
where datePayment < PAYMENTLIMIT
My question is how to calculate this PAYMENTLIMIT. Where PAYMENTLIMIT is 'the fifth working day of every month'.
The query should be run under Mysql and Oracle therefore standard SQL should be used.
Any hint?
EDIT
In order to be consistent with the title of the question the pseudo-query should the read as follows:
select count(*) from invoice
where datePayment < FIRST_WORKING_DAY + N
then the question can be reduced to calculate the FIRST_WORKING_DAY of every month.
You could look for the first date in a month, where the date is not in the holiday table and the date is not a weekend:
select min(datePayment), datepart(mm, datePayment)
from invoices
where datepart(dw, datePayment) not in (1,7) --day of week
and not exists (select holiday from holidays where holiday = datePayment)
group by datepart(mm, datePayment) --monthnr
Something like this might work:
create function dbo.GetFirstWorkdayOfMonth(#Year INT, #Month INT)
returns DATETIME
as begin
declare #firstOfMonth VARCHAR(20)
SET #firstOfMonth = CAST(#Year AS VARCHAR(4)) + '-' + CAST(#Month AS VARCHAR) + '-01'
declare #currDate DATETIME
set #currDate = CAST(#firstOfMonth as DATETIME)
declare #weekday INT
set #weekday = DATEPART(weekday, #currdate)
-- 7 = saturday, 1 = sunday
while #weekday = 1 OR #weekday = 7
begin
set #currDate = DATEADD(DAY, 1, #currDate)
set #weekday = DATEPART(weekday, #currdate)
end
return #currdate
end
I'm not 100% sure about whether the "weekday" numbers are fixed or might depend on your locale on your SQL Server. Check it out!
Marc
Rather than a Holidays table of days to exclude, we use the calendar table approach: one row for every day the application will ever need (thirty years spans a modest 11K rows). So not only does it have an is_weekday column, it has other things relevant to the enterprise e.g. julianized_date. This way, every possible date would have a ready-prepared value for first_working_day_this_month and finding it involves a simple lookup (which SQL products tend to be optimized for!) rather than 'calculating' it each time on the fly.
We have dates table in our application (filled with all dates and date parts for some tens of years), what allows various "missing" date manipulations, like (in pseudo-sql):
select min(ourdates.datevalue)
from ourdates
where ourdates.year=<given year> and ourdates.month=<given month>
and ourdates.isworkday
and not exists (
select * from holidays
where holidays.datevalue=ourdates.datevalue
)
Ok, at a first stab, you could put the following code into a UDF and pass in the Year and Month as variables. It can then return TestDate which is the first working day of the month.
DECLARE #Month INT
DECLARE #Year INT
SELECT #Month = 5
SELECT #Year = 2009
DECLARE #FirstDate DATETIME
SELECT #FirstDate = CONVERT(varchar(4), #Year) + '-' + CONVERT(varchar(2), #Month) + '-' + '01 00:00:00.000'
DROP TABLE #HOLIDAYS
CREATE TABLE #HOLIDAYS (HOLIDAY DateTime)
INSERT INTO #HOLIDAYS VALUES('2009-01-01 00:00:00.000')
INSERT INTO #HOLIDAYS VALUES('2009-05-01 00:00:00.000')
DECLARE #DateFound BIT
SELECT #DateFound = 0
WHILE(#DateFound = 0)
BEGIN
IF(
DATEPART(dw, #FirstDate) = 1
OR
DATEPART(dw, #FirstDate) = 1
OR
EXISTS(SELECT * FROM #HOLIDAYS WHERE HOLIDAY = #FirstDate)
)
BEGIN
SET #FirstDate = DATEADD(dd, 1, #FirstDate)
END
ELSE
BEGIN
SET #DateFound = 1
END
END
SELECT #FirstDate
The things I don`t like with this solution though are, if your holidays table contains all days of the month there will be an infinite loop. (You could check the loop is still looking at the right month) It relies upon the dates being equal, eg all at time 00:00:00. Finally, the way I calculate the 1st of the month past in using string concatenation was a short cut. There are much better ways of finding the actual first day of the month.
Gets the first N working days of each month of year 2009:
select * from invoices as x
where
datePayment between '2009-01-01' and '2009-12-31'
and exists
(
select
1
from invoices
where
-- exclude holidays and sunday saturday...
(
datepart(dw, datePayment) not in (1,7) -- day of week
/*
-- Postgresql and Oracle have programmer-friendly IN clause
and
(datepart(yyyy,datePayment), datepart(mm,datePayment))
not in (select hyear, hday from holidays)
*/
-- this is the MSSQL equivalent of programmer-friendly IN
and
not exists
(
select * from holidays
where
hyear = datepart(yyyy,datePayment)
and hmonth = datepart(mm, datePayment)
)
)
-- ...exclude holidays and sunday saturday
-- get the month of x datePayment
and
(datepart(yyyy, datePayment) = datepart(yyyy, x.datePayment)
and datepart(mm, datePayment) = datepart(mm, x.datePayment))
group by
datepart(yyyy, datePayment), datepart(mm, datePayment)
having
x.datePayment < MIN(datePayment) + #N -- up to N working days
)
Returns the first Monday of the current month
SELECT DATEADD(
WEEK,
DATEDIFF( --x weeks between 1900-01-01 (Monday) and inner result
WEEK,
0, --1900-01-01
DATEADD( --inner result
DAY,
6 - DATEPART(DAY, GETDATE()),
GETDATE()
)
),
0 --1900-01-01 (Monday)
)
SELECT DATEADD(day, DATEDIFF (day, 0, DATEADD (month, DATEDIFF (month, 0, GETDATE()), 0) -1)/7*7 + 7, 0);
select if(weekday('yyyy-mm-01') < 5,'yyyy-mm-01',if(weekday('yyyy-mm-02') < 5,'yyyy-mm-02','yyyy-mm-03'))
Saturdays and Sundays are 5, 6 so you only need two checks to get the first working day

SQL Server Non-Standard Date Based Histogram

I have user login data with timestamps and what I would like to do is get a histogram of logins by year, but with the year starting at an arbitrary date. For example, I want the following sort of information:
1 May 2005 - 30 Apr 2006 | 525
1 May 2006 - 30 Apr 2007 | 673
1 May 2007 - 30 Apr 2008 | 892
1 May 2006 - 30 Apr 2009 | 1047
The labels in the first column are not important, but the date ranges are. I know I can break it down by strait years with:
SELECT YEAR([date]) AS [year], COUNT(*) AS cnt
FROM logins
GROUP BY YEAR([date])
ORDER BY [year]
But that doesn't give me the data ranges I want. How can this be done?
declare #baseDate datetime
set #baseDate = '1 May 2005'
SELECT
datediff(year, #baseDate, [date]) AS YearBucket
,COUNT(*) AS cnt
FROM logins
GROUP BY datediff(year, #baseDate, [date])
ORDER BY datediff(year, #baseDate, [date])
EDIT - apologies, you are correct. Here is a fixed version (I should have used a test table to start with...)
create table logins (date datetime, foo int)
insert logins values ('1 may 2005', 1)
insert logins values ('1 apr 2006', 2)
insert logins values ('1 may 2006', 3)
declare #baseDate datetime
set #baseDate = '1 May 2005'
SELECT
datediff(day, #baseDate, [date]) / 365 AS YearBucket
,COUNT(*) AS cnt
FROM logins
GROUP BY datediff(day, #baseDate, [date]) / 365
ORDER BY datediff(day, #baseDate, [date]) / 365
Change the datediff units if you want more granularity than days.
EDIT #2 - ok, here is a more robust solution that handles leap years :)
EDIT #3 - Actually this doesn't handle leap years, instead it allows for variable intervals of time to be specified. Go with dateadd(year, 1, #baseDate) for the leap year safe approach.
declare #baseDate datetime, #interval datetime
--#interval is expressed as time above 0 time (1/1/1900)
select #baseDate = '1 May 2005', #interval = '1901'
declare #timeRanges table (beginIntervalInclusive datetime, endIntervalExclusive datetime)
declare #i int
set #i = 1
while #i <= 10
begin
insert #timeRanges values(#baseDate, #baseDate + #interval)
set #baseDate = #baseDate + #interval
set #i = #i + 1
end
SELECT
tr.beginIntervalInclusive,
tr.endIntervalExclusive,
COUNT(*) AS cnt
FROM logins join #timeRanges as tr
on logins.date >= tr.beginIntervalInclusive
and logins.date < tr.endIntervalExclusive
GROUP BY tr.beginIntervalInclusive, tr.endIntervalExclusive
ORDER BY tr.beginIntervalInclusive
If you can find a way to define your date ranges in a separate table then select out a label and two columns of dates and join on that from your main query something like this depending on your tables.
Select Count(*) as NoLogons, DateRangeLabel
From logins a
inner join
(
Select
DateRangeLabel, StartDate, EndDate
From tblMyDates
) b
on a.date between b.startdate and b.enddate
Group by DateRangeLabel