Skip to content

Instantly share code, notes, and snippets.

@foshdafosh
Forked from johngrimes/date.sql
Last active June 16, 2025 13:45
Show Gist options
  • Save foshdafosh/9a5242f3df0e01d4ad782bf1379eefc2 to your computer and use it in GitHub Desktop.
Save foshdafosh/9a5242f3df0e01d4ad782bf1379eefc2 to your computer and use it in GitHub Desktop.
MySQL Date Dimension Build Script
/* Adapted from Tom Cunningham's 'Data Warehousing with MySql' (www.meansandends.com/mysql-data-warehouse) */
###### small-numbers table
DROP TABLE IF EXISTS dim_numbers_small;
CREATE TABLE dim_numbers_small (number INT);
INSERT INTO dim_numbers_small VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
###### main numbers table
DROP TABLE IF EXISTS dim_numbers;
CREATE TABLE dim_numbers (number BIGINT);
INSERT INTO dim_numbers
SELECT thousands.number * 1000 + hundreds.number * 100 + tens.number * 10 + ones.number
FROM dim_numbers_small thousands, dim_numbers_small hundreds, dim_numbers_small tens, dim_numbers_small ones
LIMIT 1000000;
###### time table
DROP TABLE IF EXISTS dim_times;
CREATE TABLE dim_times (
time_id BIGINT PRIMARY KEY,
time TIME,
hour_12 INT,
hour_12_period CHAR(2),
hour INT,
minute INT,
core_hour INT,
standard_day INT
);
###### populate it with minutes
INSERT INTO dim_times (time_id, time)
SELECT number, DATE_ADD( '1970-01-01 00:00:00', INTERVAL number MINUTE )
FROM dim_numbers
ORDER BY number
LIMIT 1440;
UPDATE dim_times SET
hour_12 = time_format(time, '%h'),
hour_12_period = time_format(time, '%p'),
hour = hour(time),
minute = minute(time),
core_hour = if(hour between 9 and 16,1,0),
standard_day = 1
;
###### date table
/* Additional fields to add later?
isthismonth
ispreviousfullmonth
*/
DROP TABLE IF EXISTS dim_dates;
CREATE TABLE dim_dates (
date_id BIGINT PRIMARY KEY,
julian_date BIGINT,
date DATE NOT NULL,
timestamp BIGINT,
istoday INT NOT NULL DEFAULT 0,
isyesterday INT NOT NULL DEFAULT 0,
isweekend INT NOT NULL DEFAULT 0,
isworkday INT NOT NULL DEFAULT 1,
isthisweek INT NOT NULL DEFAULT 0,
islastweek INT NOT NULL DEFAULT 0,
isbankholiday INT NOT NULL DEFAULT 0,
bankholidaydesc char(20),
weekend_text CHAR(10) NOT NULL DEFAULT "Weekday",
day_of_week_full CHAR(10),
day_of_week_short CHAR(3),
day_of_week INT,
month INT,
month_full CHAR(10),
month_short CHAR(3),
first_date_of_month DATE,
last_date_of_month DATE,
days_in_month INT,
day_of_month INT,
day_of_month_text CHAR(5),
quarter INT,
year INT,
year_month_number INT,
year_quarter_number INT,
year_week_number INT,
day_of_year INT,
week_starting_monday CHAR(2),
UNIQUE KEY `date` (`date`),
KEY `year_week` (`year`,`week_starting_monday`)
);
###### populate it with days
INSERT INTO dim_dates (date_id, date)
SELECT number, DATE_ADD( '2012-01-01', INTERVAL number DAY )
FROM dim_numbers
WHERE DATE_ADD( '2012-01-01', INTERVAL number DAY ) BETWEEN '2012-01-01' AND '2022-01-01'
ORDER BY number;
###### fill in other rows
UPDATE dim_dates SET
timestamp = UNIX_TIMESTAMP(date),
julian_date = TO_DAYS(date),
day_of_week = IF(DATE_FORMAT( date, "%w" ) = 0,7,DATE_FORMAT( date, "%w" )),
day_of_week_full = DATE_FORMAT( date, "%W" ),
day_of_week_short = DATE_FORMAT( date, "%a" ),
weekend_text = IF( DATE_FORMAT( date, "%W" ) IN ('Saturday','Sunday'), 'Weekend', 'Weekday'),
istoday = IF( date = CURDATE(), 1, 0),
isyesterday = IF( date = (CURDATE()-1), 1, 0),
isweekend = IF( DATE_FORMAT( date, "%W" ) IN ('Saturday','Sunday'), 1, 0),
isworkday = IF( DATE_FORMAT( date, "%W" ) IN ('Saturday','Sunday'), 0, 1),
isthisweek = IF( YEARWEEK(date, 1) = YEARWEEK(CURDATE(), 1), 1, 0),
islastweek = IF( YEARWEEK(date, 1) = (YEARWEEK(CURDATE(), 1)-1), 1, 0),
month = DATE_FORMAT( date, "%m"),
month_full = DATE_FORMAT( date, "%M"),
month_short = DATE_FORMAT( date, "%b"),
first_date_of_month= date_add(date,interval -DAY(date)+1 DAY),
last_date_of_month = LAST_DAY(date),
days_in_month = DAY(LAST_DAY(date)),
quarter = QUARTER( date ),
year = DATE_FORMAT( date, "%Y" ),
year_month_number = CONCAT(DATE_FORMAT(date, "%Y"),DATE_FORMAT(date, "%m")),
year_quarter_number = CONCAT(DATE_FORMAT(date, "%Y"),QUARTER(date)),
year_week_number = CONCAT(DATE_FORMAT(date, "%Y"),DATE_FORMAT(date, "%v")),
day_of_month = DATE_FORMAT( date, "%d" ),
day_of_month_text = DATE_FORMAT( date, "%D" ),
day_of_year = DATE_FORMAT( date, "%j" );
###### fill in other rows - second pass
UPDATE dim_dates SET week_starting_monday = DATE_FORMAT(date,'%v');
###### ideally populate bank holidays from https://www.gov.uk/bank-holidays / https://www.gov.uk/bank-holidays/england-and-wales.ics
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment