pf_app/setup_sql/gen_dim_period.sql
Paul Trowbridge 56733df5d4 Add dim_group to col_meta and pf.dim_period calendar table
- col_meta: add dim_group field to group related columns (dimension hierarchies, date-adjacent columns); is_key now enabled for date role to mark group parent
- sources.js: upsert includes dim_group
- Setup.jsx: group column in col_meta editor, key checkbox enabled for date role
- gen_dim_period.sql: create and populate pf.dim_period with calendar and fiscal period cuts (monthly grain, 2018-2035)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 01:46:16 -04:00

95 lines
4.1 KiB
SQL

-- pf.dim_period — create and populate
-- Adjust fiscal_start_month: 1=Jan (calendar year), 4=Apr, 6=Jun, 7=Jul, 10=Oct, etc.
-- Safe to re-run: ON CONFLICT DO NOTHING, so existing rows are never overwritten.
CREATE TABLE IF NOT EXISTS pf.dim_period (
sdat date NOT NULL PRIMARY KEY,
edat date NOT NULL,
drange daterange NOT NULL,
ndays integer NOT NULL,
-- calendar
cal_year integer NOT NULL,
cal_quarter integer NOT NULL,
cal_month integer NOT NULL,
cal_month_abbr text NOT NULL, -- 01 - Jan
cal_month_name text NOT NULL, -- 01 - January
cal_label text NOT NULL, -- 2025-01 Jan
-- fiscal
fisc_year integer NOT NULL,
fisc_quarter integer NOT NULL,
fisc_quarter_label text NOT NULL, -- FY2025 Q3
fisc_month integer NOT NULL,
fisc_month_abbr text NOT NULL, -- 07 - Jan
fisc_month_name text NOT NULL, -- 07 - January
fisc_label text NOT NULL, -- FY2025 P07
-- sort key
period_key text NOT NULL -- 2025.07 (ltree-compatible)
);
CREATE INDEX IF NOT EXISTS dim_period_drange_idx ON pf.dim_period USING gist (drange);
CREATE INDEX IF NOT EXISTS dim_period_fisc_idx ON pf.dim_period (fisc_year, fisc_month);
CREATE INDEX IF NOT EXISTS dim_period_cal_idx ON pf.dim_period (cal_year, cal_month);
WITH
cfg AS (
SELECT 6 AS fiscal_start_month -- change to match your fiscal year start month
)
,periods AS (
SELECT
gs.d::date AS sdat,
(gs.d + '1 month'::interval)::date AS edat,
extract(year FROM gs.d)::int AS cal_year,
extract(month FROM gs.d)::int AS cal_month,
extract(quarter FROM gs.d)::int AS cal_quarter,
((extract(month FROM gs.d)::int - cfg.fiscal_start_month + 12) % 12) + 1
AS fisc_month,
extract(year FROM gs.d)::int
+ CASE
WHEN cfg.fiscal_start_month > 1
AND extract(month FROM gs.d)::int >= cfg.fiscal_start_month
THEN 1 ELSE 0
END AS fisc_year
FROM
generate_series('2018-01-01'::date, '2035-12-01'::date, '1 month') gs(d)
CROSS JOIN cfg
)
INSERT INTO pf.dim_period (
sdat, edat, drange, ndays,
cal_year, cal_quarter, cal_month,
cal_month_abbr, cal_month_name, cal_label,
fisc_year, fisc_quarter, fisc_quarter_label,
fisc_month, fisc_month_abbr, fisc_month_name,
fisc_label, period_key
)
SELECT
sdat,
edat,
daterange(sdat, edat) AS drange,
edat - sdat AS ndays,
cal_year,
cal_quarter,
cal_month,
to_char(cal_month, 'FM00') || ' - ' || to_char(sdat, 'Mon') AS cal_month_abbr,
to_char(cal_month, 'FM00') || ' - ' || to_char(sdat, 'Month') AS cal_month_name,
to_char(sdat, 'YYYY-MM') || ' ' || to_char(sdat, 'Mon') AS cal_label,
fisc_year,
ceil(fisc_month / 3.0)::int AS fisc_quarter,
'FY' || fisc_year || ' Q' || ceil(fisc_month / 3.0)::int AS fisc_quarter_label,
fisc_month,
to_char(fisc_month, 'FM00') || ' - ' || to_char(sdat, 'Mon') AS fisc_month_abbr,
to_char(fisc_month, 'FM00') || ' - ' || to_char(sdat, 'Month') AS fisc_month_name,
'FY' || fisc_year || ' P' || to_char(fisc_month, 'FM00') AS fisc_label,
to_char(fisc_year, 'FM0000') || '.' || to_char(fisc_month, 'FM00') AS period_key
FROM periods
ON CONFLICT (sdat) DO NOTHING;
-- preview first 24 months
SELECT
period_key, sdat, edat, ndays,
cal_year, cal_quarter, cal_month, cal_month_abbr,
fisc_year, fisc_quarter, fisc_month, fisc_month_abbr,
fisc_quarter_label, fisc_label, cal_label
FROM pf.dim_period
ORDER BY sdat
LIMIT 24;