What is the best way to rebuild a date from integer inputs?

Clash Royale CLAN TAG#URR8PPP
I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.
I'm doing it this way, but I really don't like it:
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '-01-01'
set @date = dateadd(quarter, @quarter - 1, @date)
print @date
Question What is the best way to reconstruct a date from integer inputs?
desired result:
2018-10-01
sql-server-2008-r2
add a comment |
I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.
I'm doing it this way, but I really don't like it:
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '-01-01'
set @date = dateadd(quarter, @quarter - 1, @date)
print @date
Question What is the best way to reconstruct a date from integer inputs?
desired result:
2018-10-01
sql-server-2008-r2
add a comment |
I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.
I'm doing it this way, but I really don't like it:
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '-01-01'
set @date = dateadd(quarter, @quarter - 1, @date)
print @date
Question What is the best way to reconstruct a date from integer inputs?
desired result:
2018-10-01
sql-server-2008-r2
I've got a bunch of financial reports, and we want to be able to pass them two inputs (year and quarter) as variables.
I'm doing it this way, but I really don't like it:
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '-01-01'
set @date = dateadd(quarter, @quarter - 1, @date)
print @date
Question What is the best way to reconstruct a date from integer inputs?
desired result:
2018-10-01
sql-server-2008-r2
sql-server-2008-r2
edited Jan 10 at 21:47
James
asked Jan 10 at 21:39
JamesJames
1,069728
1,069728
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
How about
declare @quarter int = 4
declare @year int = 2018
select datefromparts(@year,(@quarter-1)*3+1,1)
or if you're still using SQL 2008:
select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))
add a comment |
Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 1 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 2 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 3 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 4 - 1, @date)
print @date
2018-01-01
2018-04-01
2018-07-01
2018-10-01
db<>fiddle here
3
My understanding was, that'2018-10-01'is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?
– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous formatYYYYMMDD HH:MM:SSto avoid date conversion issues.
– McNets
Jan 11 at 8:24
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.dateanddatetime2) but not for the legacydatetimetype. So as the questioner is casting todatethe format is fine in this case
– Martin Smith
Jan 11 at 11:17
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
add a comment |
You could Create a date dimension or calendar table in SQL Server and query it
--demo setup
drop table if exists #dim
DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
CREATE TABLE #dim
(
[date] DATE PRIMARY KEY,
[day] AS DATEPART(DAY, [date]),
[month] AS DATEPART(MONTH, [date]),
FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
[MonthName] AS DATENAME(MONTH, [date]),
[week] AS DATEPART(WEEK, [date]),
[ISOweek] AS DATEPART(ISO_WEEK, [date]),
[DayOfWeek] AS DATEPART(WEEKDAY, [date]),
[quarter] AS DATEPART(QUARTER, [date]),
[year] AS DATEPART(YEAR, [date]),
FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
Style112 AS CONVERT(CHAR(8), [date], 112),
Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim([date])
SELECT d
FROM
(
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
drop table if exists dbo.DateDimension
CREATE TABLE dbo.DateDimension
(
--DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
HolidayText VARCHAR(64) SPARSE,
DOWInMonth TINYINT NOT NULL,
[DayOfYear] SMALLINT NOT NULL,
WeekOfMonth TINYINT NOT NULL,
WeekOfYear TINYINT NOT NULL,
ISOWeekOfYear TINYINT NOT NULL,
[Month] TINYINT NOT NULL,
[MonthName] VARCHAR(10) NOT NULL,
[Quarter] TINYINT NOT NULL,
QuarterName VARCHAR(6) NOT NULL,
[Year] INT NOT NULL,
MMYYYY CHAR(6) NOT NULL,
MonthYear CHAR(7) NOT NULL,
FirstDayOfMonth DATE NOT NULL,
LastDayOfMonth DATE NOT NULL,
FirstDayOfQuarter DATE NOT NULL,
LastDayOfQuarter DATE NOT NULL,
FirstDayOfYear DATE NOT NULL,
LastDayOfYear DATE NOT NULL,
FirstDayOfNextMonth DATE NOT NULL,
FirstDayOfNextYear DATE NOT NULL
);
INSERT dbo.DateDimension WITH (TABLOCKX)
SELECT
--DateKey = CONVERT(INT, Style112),
[Date] = [date],
[Day] = CONVERT(TINYINT, [day]),
DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
WHEN '3' THEN 'rd' ELSE 'th' END END),
[Weekday] = CONVERT(TINYINT, [DayOfWeek]),
[WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
[IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
[IsHoliday] = CONVERT(BIT, 0),
HolidayText = CONVERT(VARCHAR(64), NULL),
[DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
(PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
[DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
(PARTITION BY [year], [month] ORDER BY [week])),
WeekOfYear = CONVERT(TINYINT, [week]),
ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
[Month] = CONVERT(TINYINT, [month]),
[MonthName] = CONVERT(VARCHAR(10), [MonthName]),
[Quarter] = CONVERT(TINYINT, [quarter]),
QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
[Year] = [year],
MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
FirstDayOfMonth = FirstOfMonth,
LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
FirstDayOfYear = FirstOfYear,
LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
FROM #dim
OPTION (MAXDOP 1);
--solution
SELECT min(Date)
FROM [Test].[dbo].[DateDimension]
where [year] = 2018 and [Quarter]=4
| Date |
|------------|
| 2018-10-01 |
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
add a comment |
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATETIME, 0);
/* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */
SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));
This avoids string to date comparison which is messy, culture-dependent and expensive.
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "182"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f226838%2fwhat-is-the-best-way-to-rebuild-a-date-from-integer-inputs%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
How about
declare @quarter int = 4
declare @year int = 2018
select datefromparts(@year,(@quarter-1)*3+1,1)
or if you're still using SQL 2008:
select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))
add a comment |
How about
declare @quarter int = 4
declare @year int = 2018
select datefromparts(@year,(@quarter-1)*3+1,1)
or if you're still using SQL 2008:
select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))
add a comment |
How about
declare @quarter int = 4
declare @year int = 2018
select datefromparts(@year,(@quarter-1)*3+1,1)
or if you're still using SQL 2008:
select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))
How about
declare @quarter int = 4
declare @year int = 2018
select datefromparts(@year,(@quarter-1)*3+1,1)
or if you're still using SQL 2008:
select dateadd(month,(@quarter-1)*3,dateadd(year, @year-2018,'20180101'))
answered Jan 10 at 21:49
David Browne - MicrosoftDavid Browne - Microsoft
10.9k728
10.9k728
add a comment |
add a comment |
Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 1 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 2 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 3 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 4 - 1, @date)
print @date
2018-01-01
2018-04-01
2018-07-01
2018-10-01
db<>fiddle here
3
My understanding was, that'2018-10-01'is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?
– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous formatYYYYMMDD HH:MM:SSto avoid date conversion issues.
– McNets
Jan 11 at 8:24
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.dateanddatetime2) but not for the legacydatetimetype. So as the questioner is casting todatethe format is fine in this case
– Martin Smith
Jan 11 at 11:17
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
add a comment |
Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 1 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 2 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 3 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 4 - 1, @date)
print @date
2018-01-01
2018-04-01
2018-07-01
2018-10-01
db<>fiddle here
3
My understanding was, that'2018-10-01'is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?
– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous formatYYYYMMDD HH:MM:SSto avoid date conversion issues.
– McNets
Jan 11 at 8:24
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.dateanddatetime2) but not for the legacydatetimetype. So as the questioner is casting todatethe format is fine in this case
– Martin Smith
Jan 11 at 11:17
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
add a comment |
Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 1 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 2 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 3 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 4 - 1, @date)
print @date
2018-01-01
2018-04-01
2018-07-01
2018-10-01
db<>fiddle here
Let me suggest to NOT use a date separator like '-' or '/', it deppends on regional settings, use YYYYMMDD format.
declare @quarter int,
@year int,
@date date
set @quarter = 4
set @year = 2018
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 1 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 2 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 3 - 1, @date)
print @date
set @date = cast(@year as varchar(4)) + '0101'
set @date = dateadd(quarter, 4 - 1, @date)
print @date
2018-01-01
2018-04-01
2018-07-01
2018-10-01
db<>fiddle here
answered Jan 10 at 21:45
McNetsMcNets
15.5k41958
15.5k41958
3
My understanding was, that'2018-10-01'is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?
– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous formatYYYYMMDD HH:MM:SSto avoid date conversion issues.
– McNets
Jan 11 at 8:24
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.dateanddatetime2) but not for the legacydatetimetype. So as the questioner is casting todatethe format is fine in this case
– Martin Smith
Jan 11 at 11:17
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
add a comment |
3
My understanding was, that'2018-10-01'is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?
– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous formatYYYYMMDD HH:MM:SSto avoid date conversion issues.
– McNets
Jan 11 at 8:24
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.dateanddatetime2) but not for the legacydatetimetype. So as the questioner is casting todatethe format is fine in this case
– Martin Smith
Jan 11 at 11:17
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
3
3
My understanding was, that
'2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?– a_horse_with_no_name
Jan 11 at 7:03
My understanding was, that
'2018-10-01' is independent of regional settings and will always be parsed correctly by SQL Server. Isn't that true?– a_horse_with_no_name
Jan 11 at 7:03
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format
YYYYMMDD HH:MM:SS to avoid date conversion issues.– McNets
Jan 11 at 8:24
@a_horse_with_no_name it should due it is ISO 8601, but at least in my company where we use a mixed-language installation of SQL servers (English, Spanish) I ended using the less unambiguous format
YYYYMMDD HH:MM:SS to avoid date conversion issues.– McNets
Jan 11 at 8:24
5
5
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.
date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case– Martin Smith
Jan 11 at 11:17
@a_horse_with_no_name - This is correct for the newer temporal datatypes (e.g.
date and datetime2) but not for the legacy datetime type. So as the questioner is casting to date the format is fine in this case– Martin Smith
Jan 11 at 11:17
1
1
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
@MartinSmith: thanks for the clarification
– a_horse_with_no_name
Jan 11 at 11:42
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
"2001-08-12" isn't always interpreted in the way you would expect. I never worked out how but in our development environment it would interpret it as yyyy-dd-mm, and throw an out of range error for "2001-08-13". I try to avoid string-to-date conversion at all, and where it is necessary I make sure to use a month name - "12 aug 2001" is unambiguous.
– IanF1
Jan 19 at 18:47
add a comment |
You could Create a date dimension or calendar table in SQL Server and query it
--demo setup
drop table if exists #dim
DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
CREATE TABLE #dim
(
[date] DATE PRIMARY KEY,
[day] AS DATEPART(DAY, [date]),
[month] AS DATEPART(MONTH, [date]),
FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
[MonthName] AS DATENAME(MONTH, [date]),
[week] AS DATEPART(WEEK, [date]),
[ISOweek] AS DATEPART(ISO_WEEK, [date]),
[DayOfWeek] AS DATEPART(WEEKDAY, [date]),
[quarter] AS DATEPART(QUARTER, [date]),
[year] AS DATEPART(YEAR, [date]),
FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
Style112 AS CONVERT(CHAR(8), [date], 112),
Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim([date])
SELECT d
FROM
(
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
drop table if exists dbo.DateDimension
CREATE TABLE dbo.DateDimension
(
--DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
HolidayText VARCHAR(64) SPARSE,
DOWInMonth TINYINT NOT NULL,
[DayOfYear] SMALLINT NOT NULL,
WeekOfMonth TINYINT NOT NULL,
WeekOfYear TINYINT NOT NULL,
ISOWeekOfYear TINYINT NOT NULL,
[Month] TINYINT NOT NULL,
[MonthName] VARCHAR(10) NOT NULL,
[Quarter] TINYINT NOT NULL,
QuarterName VARCHAR(6) NOT NULL,
[Year] INT NOT NULL,
MMYYYY CHAR(6) NOT NULL,
MonthYear CHAR(7) NOT NULL,
FirstDayOfMonth DATE NOT NULL,
LastDayOfMonth DATE NOT NULL,
FirstDayOfQuarter DATE NOT NULL,
LastDayOfQuarter DATE NOT NULL,
FirstDayOfYear DATE NOT NULL,
LastDayOfYear DATE NOT NULL,
FirstDayOfNextMonth DATE NOT NULL,
FirstDayOfNextYear DATE NOT NULL
);
INSERT dbo.DateDimension WITH (TABLOCKX)
SELECT
--DateKey = CONVERT(INT, Style112),
[Date] = [date],
[Day] = CONVERT(TINYINT, [day]),
DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
WHEN '3' THEN 'rd' ELSE 'th' END END),
[Weekday] = CONVERT(TINYINT, [DayOfWeek]),
[WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
[IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
[IsHoliday] = CONVERT(BIT, 0),
HolidayText = CONVERT(VARCHAR(64), NULL),
[DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
(PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
[DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
(PARTITION BY [year], [month] ORDER BY [week])),
WeekOfYear = CONVERT(TINYINT, [week]),
ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
[Month] = CONVERT(TINYINT, [month]),
[MonthName] = CONVERT(VARCHAR(10), [MonthName]),
[Quarter] = CONVERT(TINYINT, [quarter]),
QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
[Year] = [year],
MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
FirstDayOfMonth = FirstOfMonth,
LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
FirstDayOfYear = FirstOfYear,
LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
FROM #dim
OPTION (MAXDOP 1);
--solution
SELECT min(Date)
FROM [Test].[dbo].[DateDimension]
where [year] = 2018 and [Quarter]=4
| Date |
|------------|
| 2018-10-01 |
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
add a comment |
You could Create a date dimension or calendar table in SQL Server and query it
--demo setup
drop table if exists #dim
DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
CREATE TABLE #dim
(
[date] DATE PRIMARY KEY,
[day] AS DATEPART(DAY, [date]),
[month] AS DATEPART(MONTH, [date]),
FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
[MonthName] AS DATENAME(MONTH, [date]),
[week] AS DATEPART(WEEK, [date]),
[ISOweek] AS DATEPART(ISO_WEEK, [date]),
[DayOfWeek] AS DATEPART(WEEKDAY, [date]),
[quarter] AS DATEPART(QUARTER, [date]),
[year] AS DATEPART(YEAR, [date]),
FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
Style112 AS CONVERT(CHAR(8), [date], 112),
Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim([date])
SELECT d
FROM
(
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
drop table if exists dbo.DateDimension
CREATE TABLE dbo.DateDimension
(
--DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
HolidayText VARCHAR(64) SPARSE,
DOWInMonth TINYINT NOT NULL,
[DayOfYear] SMALLINT NOT NULL,
WeekOfMonth TINYINT NOT NULL,
WeekOfYear TINYINT NOT NULL,
ISOWeekOfYear TINYINT NOT NULL,
[Month] TINYINT NOT NULL,
[MonthName] VARCHAR(10) NOT NULL,
[Quarter] TINYINT NOT NULL,
QuarterName VARCHAR(6) NOT NULL,
[Year] INT NOT NULL,
MMYYYY CHAR(6) NOT NULL,
MonthYear CHAR(7) NOT NULL,
FirstDayOfMonth DATE NOT NULL,
LastDayOfMonth DATE NOT NULL,
FirstDayOfQuarter DATE NOT NULL,
LastDayOfQuarter DATE NOT NULL,
FirstDayOfYear DATE NOT NULL,
LastDayOfYear DATE NOT NULL,
FirstDayOfNextMonth DATE NOT NULL,
FirstDayOfNextYear DATE NOT NULL
);
INSERT dbo.DateDimension WITH (TABLOCKX)
SELECT
--DateKey = CONVERT(INT, Style112),
[Date] = [date],
[Day] = CONVERT(TINYINT, [day]),
DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
WHEN '3' THEN 'rd' ELSE 'th' END END),
[Weekday] = CONVERT(TINYINT, [DayOfWeek]),
[WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
[IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
[IsHoliday] = CONVERT(BIT, 0),
HolidayText = CONVERT(VARCHAR(64), NULL),
[DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
(PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
[DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
(PARTITION BY [year], [month] ORDER BY [week])),
WeekOfYear = CONVERT(TINYINT, [week]),
ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
[Month] = CONVERT(TINYINT, [month]),
[MonthName] = CONVERT(VARCHAR(10), [MonthName]),
[Quarter] = CONVERT(TINYINT, [quarter]),
QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
[Year] = [year],
MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
FirstDayOfMonth = FirstOfMonth,
LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
FirstDayOfYear = FirstOfYear,
LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
FROM #dim
OPTION (MAXDOP 1);
--solution
SELECT min(Date)
FROM [Test].[dbo].[DateDimension]
where [year] = 2018 and [Quarter]=4
| Date |
|------------|
| 2018-10-01 |
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
add a comment |
You could Create a date dimension or calendar table in SQL Server and query it
--demo setup
drop table if exists #dim
DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
CREATE TABLE #dim
(
[date] DATE PRIMARY KEY,
[day] AS DATEPART(DAY, [date]),
[month] AS DATEPART(MONTH, [date]),
FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
[MonthName] AS DATENAME(MONTH, [date]),
[week] AS DATEPART(WEEK, [date]),
[ISOweek] AS DATEPART(ISO_WEEK, [date]),
[DayOfWeek] AS DATEPART(WEEKDAY, [date]),
[quarter] AS DATEPART(QUARTER, [date]),
[year] AS DATEPART(YEAR, [date]),
FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
Style112 AS CONVERT(CHAR(8), [date], 112),
Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim([date])
SELECT d
FROM
(
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
drop table if exists dbo.DateDimension
CREATE TABLE dbo.DateDimension
(
--DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
HolidayText VARCHAR(64) SPARSE,
DOWInMonth TINYINT NOT NULL,
[DayOfYear] SMALLINT NOT NULL,
WeekOfMonth TINYINT NOT NULL,
WeekOfYear TINYINT NOT NULL,
ISOWeekOfYear TINYINT NOT NULL,
[Month] TINYINT NOT NULL,
[MonthName] VARCHAR(10) NOT NULL,
[Quarter] TINYINT NOT NULL,
QuarterName VARCHAR(6) NOT NULL,
[Year] INT NOT NULL,
MMYYYY CHAR(6) NOT NULL,
MonthYear CHAR(7) NOT NULL,
FirstDayOfMonth DATE NOT NULL,
LastDayOfMonth DATE NOT NULL,
FirstDayOfQuarter DATE NOT NULL,
LastDayOfQuarter DATE NOT NULL,
FirstDayOfYear DATE NOT NULL,
LastDayOfYear DATE NOT NULL,
FirstDayOfNextMonth DATE NOT NULL,
FirstDayOfNextYear DATE NOT NULL
);
INSERT dbo.DateDimension WITH (TABLOCKX)
SELECT
--DateKey = CONVERT(INT, Style112),
[Date] = [date],
[Day] = CONVERT(TINYINT, [day]),
DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
WHEN '3' THEN 'rd' ELSE 'th' END END),
[Weekday] = CONVERT(TINYINT, [DayOfWeek]),
[WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
[IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
[IsHoliday] = CONVERT(BIT, 0),
HolidayText = CONVERT(VARCHAR(64), NULL),
[DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
(PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
[DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
(PARTITION BY [year], [month] ORDER BY [week])),
WeekOfYear = CONVERT(TINYINT, [week]),
ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
[Month] = CONVERT(TINYINT, [month]),
[MonthName] = CONVERT(VARCHAR(10), [MonthName]),
[Quarter] = CONVERT(TINYINT, [quarter]),
QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
[Year] = [year],
MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
FirstDayOfMonth = FirstOfMonth,
LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
FirstDayOfYear = FirstOfYear,
LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
FROM #dim
OPTION (MAXDOP 1);
--solution
SELECT min(Date)
FROM [Test].[dbo].[DateDimension]
where [year] = 2018 and [Quarter]=4
| Date |
|------------|
| 2018-10-01 |
You could Create a date dimension or calendar table in SQL Server and query it
--demo setup
drop table if exists #dim
DECLARE @StartDate DATE = '20000101', @NumberOfYears INT = 30;
-- prevent set or regional settings from interfering with
-- interpretation of dates / literals
SET DATEFIRST 7;
SET DATEFORMAT mdy;
SET LANGUAGE US_ENGLISH;
DECLARE @CutoffDate DATE = DATEADD(YEAR, @NumberOfYears, @StartDate);
-- this is just a holding table for intermediate calculations:
CREATE TABLE #dim
(
[date] DATE PRIMARY KEY,
[day] AS DATEPART(DAY, [date]),
[month] AS DATEPART(MONTH, [date]),
FirstOfMonth AS CONVERT(DATE, DATEADD(MONTH, DATEDIFF(MONTH, 0, [date]), 0)),
[MonthName] AS DATENAME(MONTH, [date]),
[week] AS DATEPART(WEEK, [date]),
[ISOweek] AS DATEPART(ISO_WEEK, [date]),
[DayOfWeek] AS DATEPART(WEEKDAY, [date]),
[quarter] AS DATEPART(QUARTER, [date]),
[year] AS DATEPART(YEAR, [date]),
FirstOfYear AS CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, [date]), 0)),
Style112 AS CONVERT(CHAR(8), [date], 112),
Style101 AS CONVERT(CHAR(10), [date], 101)
);
-- use the catalog views to generate as many rows as we need
INSERT #dim([date])
SELECT d
FROM
(
SELECT d = DATEADD(DAY, rn - 1, @StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
drop table if exists dbo.DateDimension
CREATE TABLE dbo.DateDimension
(
--DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
HolidayText VARCHAR(64) SPARSE,
DOWInMonth TINYINT NOT NULL,
[DayOfYear] SMALLINT NOT NULL,
WeekOfMonth TINYINT NOT NULL,
WeekOfYear TINYINT NOT NULL,
ISOWeekOfYear TINYINT NOT NULL,
[Month] TINYINT NOT NULL,
[MonthName] VARCHAR(10) NOT NULL,
[Quarter] TINYINT NOT NULL,
QuarterName VARCHAR(6) NOT NULL,
[Year] INT NOT NULL,
MMYYYY CHAR(6) NOT NULL,
MonthYear CHAR(7) NOT NULL,
FirstDayOfMonth DATE NOT NULL,
LastDayOfMonth DATE NOT NULL,
FirstDayOfQuarter DATE NOT NULL,
LastDayOfQuarter DATE NOT NULL,
FirstDayOfYear DATE NOT NULL,
LastDayOfYear DATE NOT NULL,
FirstDayOfNextMonth DATE NOT NULL,
FirstDayOfNextYear DATE NOT NULL
);
INSERT dbo.DateDimension WITH (TABLOCKX)
SELECT
--DateKey = CONVERT(INT, Style112),
[Date] = [date],
[Day] = CONVERT(TINYINT, [day]),
DaySuffix = CONVERT(CHAR(2), CASE WHEN [day] / 10 = 1 THEN 'th' ELSE
CASE RIGHT([day], 1) WHEN '1' THEN 'st' WHEN '2' THEN 'nd'
WHEN '3' THEN 'rd' ELSE 'th' END END),
[Weekday] = CONVERT(TINYINT, [DayOfWeek]),
[WeekDayName] = CONVERT(VARCHAR(10), DATENAME(WEEKDAY, [date])),
[IsWeekend] = CONVERT(BIT, CASE WHEN [DayOfWeek] IN (1,7) THEN 1 ELSE 0 END),
[IsHoliday] = CONVERT(BIT, 0),
HolidayText = CONVERT(VARCHAR(64), NULL),
[DOWInMonth] = CONVERT(TINYINT, ROW_NUMBER() OVER
(PARTITION BY FirstOfMonth, [DayOfWeek] ORDER BY [date])),
[DayOfYear] = CONVERT(SMALLINT, DATEPART(DAYOFYEAR, [date])),
WeekOfMonth = CONVERT(TINYINT, DENSE_RANK() OVER
(PARTITION BY [year], [month] ORDER BY [week])),
WeekOfYear = CONVERT(TINYINT, [week]),
ISOWeekOfYear = CONVERT(TINYINT, ISOWeek),
[Month] = CONVERT(TINYINT, [month]),
[MonthName] = CONVERT(VARCHAR(10), [MonthName]),
[Quarter] = CONVERT(TINYINT, [quarter]),
QuarterName = CONVERT(VARCHAR(6), CASE [quarter] WHEN 1 THEN 'First'
WHEN 2 THEN 'Second' WHEN 3 THEN 'Third' WHEN 4 THEN 'Fourth' END),
[Year] = [year],
MMYYYY = CONVERT(CHAR(6), LEFT(Style101, 2) + LEFT(Style112, 4)),
MonthYear = CONVERT(CHAR(7), LEFT([MonthName], 3) + LEFT(Style112, 4)),
FirstDayOfMonth = FirstOfMonth,
LastDayOfMonth = MAX([date]) OVER (PARTITION BY [year], [month]),
FirstDayOfQuarter = MIN([date]) OVER (PARTITION BY [year], [quarter]),
LastDayOfQuarter = MAX([date]) OVER (PARTITION BY [year], [quarter]),
FirstDayOfYear = FirstOfYear,
LastDayOfYear = MAX([date]) OVER (PARTITION BY [year]),
FirstDayOfNextMonth = DATEADD(MONTH, 1, FirstOfMonth),
FirstDayOfNextYear = DATEADD(YEAR, 1, FirstOfYear)
FROM #dim
OPTION (MAXDOP 1);
--solution
SELECT min(Date)
FROM [Test].[dbo].[DateDimension]
where [year] = 2018 and [Quarter]=4
| Date |
|------------|
| 2018-10-01 |
answered Jan 10 at 21:51
Scott HodginScott Hodgin
17k21534
17k21534
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
add a comment |
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
1
1
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
This is the right way to do it - this way we can index the date parts, so it will be a bazillion times faster to join to DateDimension than to put a function on a column in the where clause.
– James
Jan 11 at 15:41
add a comment |
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATETIME, 0);
/* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */
SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));
This avoids string to date comparison which is messy, culture-dependent and expensive.
add a comment |
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATETIME, 0);
/* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */
SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));
This avoids string to date comparison which is messy, culture-dependent and expensive.
add a comment |
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATETIME, 0);
/* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */
SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));
This avoids string to date comparison which is messy, culture-dependent and expensive.
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATETIME, 0);
/* for some reason SQL Server let's you cast int to datetime but not to date, the above casts via datetime (second cast implicit) */
SET @date = DATEADD(MONTH, (@quarter-1)*3, DATEADD(YEAR, @year - YEAR(@epoch), @epoch));
This avoids string to date comparison which is messy, culture-dependent and expensive.
edited Jan 11 at 19:10
answered Jan 11 at 6:53
IanF1IanF1
1313
1313
add a comment |
add a comment |
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f226838%2fwhat-is-the-best-way-to-rebuild-a-date-from-integer-inputs%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown