Sql-Server-2008-R2

從整數輸入重建日期的最佳方法是什麼?

  • January 11, 2019

我有一堆財務報告,我們希望能夠將兩個輸入(年份和季度)作為變數傳遞給它們。

我正在這樣做,但我真的不喜歡它:

   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

問題從整數輸入重建日期的最佳方法是什麼?

期望的結果:

   2018-10-01

您可以在 SQL Server 中創建日期維度或日曆表並對其進行查詢

--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 |

引用自:https://dba.stackexchange.com/questions/226838