|
| 1 | +IF OBJECT_ID(N'proc_ssd_dim_date', N'P') IS NULL |
| 2 | + EXEC(N'CREATE PROCEDURE proc_ssd_dim_date AS BEGIN SET NOCOUNT ON; RETURN; END'); |
| 3 | +GO |
| 4 | +CREATE OR ALTER PROCEDURE proc_ssd_dim_date |
| 5 | + @src_db sysname = NULL, |
| 6 | + @src_schema sysname = NULL, |
| 7 | + @ssd_timeframe_years int = NULL, |
| 8 | + @ssd_sub1_range_years int = NULL, |
| 9 | + @today_date date = NULL, |
| 10 | + @today_dt datetime = NULL, |
| 11 | + @ssd_window_start date = NULL, |
| 12 | + @ssd_window_end date = NULL, |
| 13 | + @CaseloadLastSept30th date = NULL, |
| 14 | + @CaseloadTimeframeStartDate date = NULL |
| 15 | + |
| 16 | +AS |
| 17 | +BEGIN |
| 18 | + SET NOCOUNT ON; |
| 19 | + -- normalise defaults if not provided |
| 20 | + IF @src_db IS NULL SET @src_db = DB_NAME(); |
| 21 | + IF @src_schema IS NULL SET @src_schema = SCHEMA_NAME(); |
| 22 | + IF @ssd_timeframe_years IS NULL SET @ssd_timeframe_years = 6; |
| 23 | + IF @ssd_sub1_range_years IS NULL SET @ssd_sub1_range_years = 1; |
| 24 | + IF @today_date IS NULL SET @today_date = CONVERT(date, GETDATE()); |
| 25 | + IF @today_dt IS NULL SET @today_dt = CONVERT(datetime, @today_date); |
| 26 | + IF @ssd_window_end IS NULL SET @ssd_window_end = @today_date; |
| 27 | + IF @ssd_window_start IS NULL SET @ssd_window_start = DATEADD(year, -@ssd_timeframe_years, @ssd_window_end); |
| 28 | + IF @CaseloadLastSept30th IS NULL SET @CaseloadLastSept30th = CASE |
| 29 | + WHEN @today_date > DATEFROMPARTS(YEAR(@today_date), 9, 30) THEN DATEFROMPARTS(YEAR(@today_date), 9, 30) |
| 30 | + ELSE DATEFROMPARTS(YEAR(@today_date) - 1, 9, 30) END; |
| 31 | + IF @CaseloadTimeframeStartDate IS NULL SET @CaseloadTimeframeStartDate = DATEADD(year, -@ssd_timeframe_years, @CaseloadLastSept30th); |
| 32 | + |
| 33 | + BEGIN TRY |
| 34 | +-- ============================================================================= |
| 35 | +-- Description: Centralised time-frame references for SSD and upstream reporting|tools |
| 36 | +-- Author: D2I |
| 37 | +-- Version: 1.0 |
| 38 | +-- Status: [D]ev- |
| 39 | +-- Remarks: [EA_API_PRIORITY_TABLE] |
| 40 | +-- This is a new inclusion for the SSD and as such is being phased in. |
| 41 | +-- Added here for both visibility and LA feedback, but not yet fully integrated. |
| 42 | +-- The table set to replace declarations within: META-ELEMENT: {"type": "ssd_timeframe"} |
| 43 | +-- Dependencies: |
| 44 | +-- |
| 45 | +-- ============================================================================= |
| 46 | + |
| 47 | + |
| 48 | +IF OBJECT_ID('ssd_dim_date', 'U') IS NOT NULL |
| 49 | + DROP TABLE ssd_dim_date; |
| 50 | + |
| 51 | +CREATE TABLE ssd_dim_date |
| 52 | +( |
| 53 | + date_key int NOT NULL, -- yyyymmdd |
| 54 | + full_date date NOT NULL, -- upstream JSON processing use ISO 8601, DfE/Ofted style dd/mm/yyyy |
| 55 | + |
| 56 | + calendar_year int NOT NULL, |
| 57 | + calendar_quarter tinyint NOT NULL, |
| 58 | + month_number tinyint NOT NULL, |
| 59 | + day_of_month tinyint NOT NULL, |
| 60 | + |
| 61 | + iso_year int NOT NULL, -- ISO-8601 week-based year |
| 62 | + iso_week tinyint NOT NULL, -- ISO week number (1-53) |
| 63 | + |
| 64 | + day_of_week_monday1 tinyint NOT NULL, -- Monday=1..Sunday=7, consistent across DATEFIRST settings |
| 65 | + is_weekend bit NOT NULL, |
| 66 | + |
| 67 | + month_start_date date NOT NULL, |
| 68 | + month_end_date date NOT NULL, |
| 69 | + quarter_start_date date NOT NULL, |
| 70 | + quarter_end_date date NOT NULL, |
| 71 | + year_start_date date NOT NULL, |
| 72 | + year_end_date date NOT NULL, |
| 73 | + |
| 74 | + fiscal_year_start_year int NOT NULL, -- eg 2025 for FY 2025/26 |
| 75 | + fiscal_year_label varchar(7) NOT NULL, -- eg '2025/26' |
| 76 | + fiscal_year_start_date date NOT NULL, -- 1 April |
| 77 | + fiscal_year_end_date date NOT NULL, -- 31 March |
| 78 | + |
| 79 | + fiscal_quarter tinyint NOT NULL, -- Q1=Apr-Jun |
| 80 | + fiscal_quarter_start_date date NOT NULL, |
| 81 | + fiscal_quarter_end_date date NOT NULL, |
| 82 | + |
| 83 | + CONSTRAINT PK_ssd_dim_date PRIMARY KEY CLUSTERED (date_key), |
| 84 | + CONSTRAINT UQ_ssd_dim_date_full_date UNIQUE (full_date) |
| 85 | +); |
| 86 | + |
| 87 | +DECLARE @StartDate date = '2015-01-01'; |
| 88 | +DECLARE @EndDate date = CONVERT(date, GETDATE()); -- end at today |
| 89 | + |
| 90 | +;WITH N AS |
| 91 | +( |
| 92 | + SELECT TOP (DATEDIFF(day, @StartDate, @EndDate) + 1) |
| 93 | + ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS n |
| 94 | + FROM sys.all_objects a |
| 95 | + CROSS JOIN sys.all_objects b |
| 96 | +), |
| 97 | +D AS |
| 98 | +( |
| 99 | + SELECT DATEADD(day, n, @StartDate) AS d |
| 100 | + FROM N |
| 101 | +), |
| 102 | +Base AS |
| 103 | +( |
| 104 | + SELECT |
| 105 | + d.d AS full_date, |
| 106 | + CONVERT(int, CONVERT(char(8), d.d, 112)) AS date_key, |
| 107 | + |
| 108 | + YEAR(d.d) AS calendar_year, |
| 109 | + DATEPART(quarter, d.d) AS calendar_quarter, |
| 110 | + MONTH(d.d) AS month_number, |
| 111 | + DAY(d.d) AS day_of_month, |
| 112 | + |
| 113 | + DATEPART(ISO_WEEK, d.d) AS iso_week, |
| 114 | + /* ISO year = year of Thursday in the ISO week, weekday use Monday=1..Sunday=7 */ |
| 115 | + YEAR(DATEADD(day, 4 - ((DATEDIFF(day, '19000101', d.d) % 7) + 1), d.d)) AS iso_year, |
| 116 | + |
| 117 | + |
| 118 | + /* Monday=1..Sunday=7, independent of server DATEFIRST */ |
| 119 | + ((DATEDIFF(day, '19000101', d.d) % 7) + 1) AS day_of_week_monday1, |
| 120 | + |
| 121 | + DATEFROMPARTS(YEAR(d.d), MONTH(d.d), 1) AS month_start_date, |
| 122 | + DATEADD(day, -1, DATEADD(month, 1, DATEFROMPARTS(YEAR(d.d), MONTH(d.d), 1))) AS month_end_date, |
| 123 | + |
| 124 | + DATEFROMPARTS(YEAR(d.d), ((DATEPART(quarter, d.d) - 1) * 3) + 1, 1) AS quarter_start_date, |
| 125 | + DATEADD(day, -1, DATEADD(month, 3, DATEFROMPARTS(YEAR(d.d), ((DATEPART(quarter, d.d) - 1) * 3) + 1, 1))) AS quarter_end_date, |
| 126 | + |
| 127 | + DATEFROMPARTS(YEAR(d.d), 1, 1) AS year_start_date, |
| 128 | + DATEFROMPARTS(YEAR(d.d), 12, 31) AS year_end_date, |
| 129 | + |
| 130 | + /* UK FY starts 1 April */ |
| 131 | + CASE WHEN MONTH(d.d) >= 4 THEN YEAR(d.d) ELSE YEAR(d.d) - 1 END AS fiscal_year_start_year |
| 132 | + FROM D d |
| 133 | +) |
| 134 | +INSERT ssd_dim_date |
| 135 | +( |
| 136 | + date_key, |
| 137 | + full_date, |
| 138 | + |
| 139 | + calendar_year, |
| 140 | + calendar_quarter, |
| 141 | + month_number, |
| 142 | + day_of_month, |
| 143 | + |
| 144 | + iso_year, |
| 145 | + iso_week, |
| 146 | + |
| 147 | + day_of_week_monday1, |
| 148 | + is_weekend, |
| 149 | + |
| 150 | + month_start_date, |
| 151 | + month_end_date, |
| 152 | + quarter_start_date, |
| 153 | + quarter_end_date, |
| 154 | + year_start_date, |
| 155 | + year_end_date, |
| 156 | + |
| 157 | + fiscal_year_start_year, |
| 158 | + fiscal_year_label, |
| 159 | + fiscal_year_start_date, |
| 160 | + fiscal_year_end_date, |
| 161 | + |
| 162 | + fiscal_quarter, |
| 163 | + fiscal_quarter_start_date, |
| 164 | + fiscal_quarter_end_date |
| 165 | +) |
| 166 | +SELECT |
| 167 | + b.date_key, |
| 168 | + b.full_date, |
| 169 | + |
| 170 | + b.calendar_year, |
| 171 | + b.calendar_quarter, |
| 172 | + b.month_number, |
| 173 | + b.day_of_month, |
| 174 | + |
| 175 | + b.iso_year, |
| 176 | + b.iso_week, |
| 177 | + |
| 178 | + b.day_of_week_monday1, |
| 179 | + CASE WHEN b.day_of_week_monday1 IN (6, 7) THEN 1 ELSE 0 END AS is_weekend, |
| 180 | + |
| 181 | + b.month_start_date, |
| 182 | + b.month_end_date, |
| 183 | + b.quarter_start_date, |
| 184 | + b.quarter_end_date, |
| 185 | + b.year_start_date, |
| 186 | + b.year_end_date, |
| 187 | + |
| 188 | + b.fiscal_year_start_year, |
| 189 | + |
| 190 | + CONCAT( |
| 191 | + b.fiscal_year_start_year, |
| 192 | + '/', |
| 193 | + RIGHT(CONVERT(varchar(4), b.fiscal_year_start_year + 1), 2) |
| 194 | + ) AS fiscal_year_label, |
| 195 | + |
| 196 | + DATEFROMPARTS(b.fiscal_year_start_year, 4, 1) AS fiscal_year_start_date, |
| 197 | + DATEADD(day, -1, DATEFROMPARTS(b.fiscal_year_start_year + 1, 4, 1)) AS fiscal_year_end_date, |
| 198 | + |
| 199 | + CASE |
| 200 | + WHEN b.month_number BETWEEN 4 AND 6 THEN 1 |
| 201 | + WHEN b.month_number BETWEEN 7 AND 9 THEN 2 |
| 202 | + WHEN b.month_number BETWEEN 10 AND 12 THEN 3 |
| 203 | + ELSE 4 |
| 204 | + END AS fiscal_quarter, |
| 205 | + |
| 206 | + CASE |
| 207 | + WHEN b.month_number BETWEEN 4 AND 6 THEN DATEFROMPARTS(b.fiscal_year_start_year, 4, 1) |
| 208 | + WHEN b.month_number BETWEEN 7 AND 9 THEN DATEFROMPARTS(b.fiscal_year_start_year, 7, 1) |
| 209 | + WHEN b.month_number BETWEEN 10 AND 12 THEN DATEFROMPARTS(b.fiscal_year_start_year, 10, 1) |
| 210 | + ELSE DATEFROMPARTS(b.fiscal_year_start_year + 1, 1, 1) |
| 211 | + END AS fiscal_quarter_start_date, |
| 212 | + |
| 213 | + DATEADD(day, -1, DATEADD(month, 3, |
| 214 | + CASE |
| 215 | + WHEN b.month_number BETWEEN 4 AND 6 THEN DATEFROMPARTS(b.fiscal_year_start_year, 4, 1) |
| 216 | + WHEN b.month_number BETWEEN 7 AND 9 THEN DATEFROMPARTS(b.fiscal_year_start_year, 7, 1) |
| 217 | + WHEN b.month_number BETWEEN 10 AND 12 THEN DATEFROMPARTS(b.fiscal_year_start_year, 10, 1) |
| 218 | + ELSE DATEFROMPARTS(b.fiscal_year_start_year + 1, 1, 1) |
| 219 | + END |
| 220 | + )) AS fiscal_quarter_end_date |
| 221 | +FROM Base b; |
| 222 | + |
| 223 | +-- -- Suggested indexes as required |
| 224 | +-- CREATE INDEX IX_ssd_dim_date_full_date |
| 225 | +-- ON ssd_dim_date (full_date) |
| 226 | +-- INCLUDE (date_key, fiscal_year_start_date, fiscal_year_end_date, fiscal_quarter, fiscal_quarter_start_date, fiscal_quarter_end_date); |
| 227 | + |
| 228 | +-- CREATE INDEX IX_ssd_dim_date_fyq |
| 229 | +-- ON ssd_dim_date (fiscal_year_start_year, fiscal_quarter) |
| 230 | +-- INCLUDE (full_date, fiscal_quarter_start_date, fiscal_quarter_end_date); |
| 231 | + |
| 232 | +-- CREATE INDEX IX_ssd_dim_date_fy |
| 233 | +-- ON ssd_dim_date (fiscal_year_start_year) |
| 234 | +-- INCLUDE (full_date, fiscal_year_start_date, fiscal_year_end_date); |
| 235 | + |
| 236 | +-- CREATE INDEX IX_ssd_dim_date_iso_year_week |
| 237 | +-- ON ssd_dim_date (iso_year, iso_week) |
| 238 | +-- INCLUDE (full_date, date_key); |
| 239 | +-- GO |
| 240 | + |
| 241 | +CREATE OR ALTER VIEW ssd_vw_current_time_windows |
| 242 | +AS |
| 243 | +WITH x AS |
| 244 | +( |
| 245 | + SELECT CONVERT(date, GETDATE()) AS run_date |
| 246 | +), |
| 247 | +p AS |
| 248 | +( |
| 249 | + /* Centralised params */ |
| 250 | + SELECT |
| 251 | + CAST(24 AS int) AS ea_months_back, -- Early Adopters |
| 252 | + CAST(6 AS int) AS ssd_timeframe_years -- SSD main |
| 253 | +) |
| 254 | +SELECT |
| 255 | + x.run_date AS ssd_run_date, |
| 256 | + |
| 257 | + /* SSD main timeframe (start and end exclusive) */ |
| 258 | + DATEADD(year, -p.ssd_timeframe_years, x.run_date) AS ssd_window_start, |
| 259 | + DATEADD(day, 1, x.run_date) AS ssd_window_end, |
| 260 | + |
| 261 | + /* EA window (24 months back, then FY start for that anchor date) */ |
| 262 | + p.ea_months_back AS ea_months_back, |
| 263 | + DATEADD(month, -p.ea_months_back, x.run_date) AS ea_anchor_date, |
| 264 | + ea.fiscal_year_start_date AS ea_window_start, |
| 265 | + DATEADD(day, 1, x.run_date) AS ea_window_end, |
| 266 | + |
| 267 | + /* Caseload anchor (last Sept 30 on or before run_date) */ |
| 268 | + p.ssd_timeframe_years AS ssd_timeframe_years, |
| 269 | + caseload.last_sept30 AS sw_caseload_anchor, |
| 270 | + DATEADD(year, -p.ssd_timeframe_years, caseload.last_sept30) AS sw_caseload_window_start |
| 271 | +FROM x |
| 272 | +CROSS JOIN p |
| 273 | +JOIN ssd_dim_date ea |
| 274 | + ON ea.full_date = DATEADD(month, -p.ea_months_back, x.run_date) |
| 275 | +CROSS APPLY |
| 276 | +( |
| 277 | + SELECT MAX(d.full_date) AS last_sept30 |
| 278 | + FROM ssd_dim_date d |
| 279 | + WHERE d.month_number = 9 |
| 280 | + AND d.day_of_month = 30 |
| 281 | + AND d.full_date <= x.run_date |
| 282 | +) caseload; |
| 283 | + |
| 284 | + |
| 285 | +select * from ssd_vw_current_time_windows; |
| 286 | + |
| 287 | + END TRY |
| 288 | + BEGIN CATCH |
| 289 | + IF XACT_STATE() <> 0 ROLLBACK TRANSACTION; |
| 290 | + DECLARE @ErrMsg nvarchar(2048) = ERROR_MESSAGE(); |
| 291 | + DECLARE @ErrSev int = ERROR_SEVERITY(); |
| 292 | + DECLARE @ErrState int = ERROR_STATE(); |
| 293 | + RAISERROR(@ErrMsg, @ErrSev, @ErrState); |
| 294 | + END CATCH |
| 295 | +END |
| 296 | +GO |
0 commit comments