What is the best way to rebuild a date from integer inputs?
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 11 hours ago
James
asked 11 hours ago
JamesJames
1,004726
1,004726
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
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
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
2 hours ago
@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:SS
to avoid date conversion issues.
– McNets
52 mins ago
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 |
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 |
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(DATE, 0);
/* can't remember if you can cast straight from int to date, if not go via datetime*/
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.
New contributor
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
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
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
2 hours ago
@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:SS
to avoid date conversion issues.
– McNets
52 mins ago
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
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
2 hours ago
@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:SS
to avoid date conversion issues.
– McNets
52 mins ago
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 11 hours ago
McNetsMcNets
15.1k41858
15.1k41858
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
2 hours ago
@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:SS
to avoid date conversion issues.
– McNets
52 mins ago
add a comment |
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
2 hours ago
@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:SS
to avoid date conversion issues.
– McNets
52 mins ago
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
2 hours ago
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
2 hours ago
@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
52 mins ago
@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
52 mins ago
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'))
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 11 hours ago
David Browne - MicrosoftDavid Browne - Microsoft
10.6k726
10.6k726
add a comment |
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 |
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 |
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 11 hours ago
Scott HodginScott Hodgin
16.9k21534
16.9k21534
add a comment |
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(DATE, 0);
/* can't remember if you can cast straight from int to date, if not go via datetime*/
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.
New contributor
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(DATE, 0);
/* can't remember if you can cast straight from int to date, if not go via datetime*/
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.
New contributor
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(DATE, 0);
/* can't remember if you can cast straight from int to date, if not go via datetime*/
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.
New contributor
I would avoid using strings at all but use date arithmetic combined with a known (or even unknown!) zero epoch.
DECLARE @epoch DATE = CONVERT(DATE, 0);
/* can't remember if you can cast straight from int to date, if not go via datetime*/
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.
New contributor
New contributor
answered 2 hours ago
IanF1IanF1
1011
1011
New contributor
New contributor
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