多条告白如次剧本只需引入一次
前天咱们经过一段代码展现了怎样经过Python的Pandas包天生一个日历表,即使诸位感爱好不妨参考:经过Pandas天生日历表;
不得不说在 DB Engine(https://db-engines.com/en/ranking)排行榜中,PostgreSQL迩来几年从来都很宁静,而且在各个云平台中都有特殊老练的PaaS产物供各个企业运用,那么咱们即日的目的即是演练一下怎样经过#postgresql#来天生一致的日历表。
正文运用的PostgreSQL本子为14.1,Windows Server 2016情况下运转。
DB Engine Ranking
少许要害的功效
GENERATE_SERIES
在实行处置计划之前,咱们先领会PostgreSQL的一个因变量:“GENERATE_SERIES”,经过字面道理该当能大概猜出来,这个因变量不妨天生一个序列的数据,直白讲即是天生单列的一个数据表。
咱们先经过psql吩咐获得对于此因变量的刻画,如次图所示:
GENERATE_SERIES Description in psql
此因变量重要有几个特性:
不妨归来整型(bigint,int),浮点典型(numeric)序列;不妨归来带时区的功夫戳典型(timestamp)序列;不妨归来不带时区的功夫戳典型(timestamp)序列;大略举个例子:
1.1 归来整型序列
当指定开始,尽头参数SELECT GENERATE_SERIES(1, 10);截止如次所示:
归来整型序列
当指定开始,尽头,步长参数步长不妨领会为腾跃值,从1发端,即使步长为2,那么下一个数字该当是1 + 2 = 3,以该类推;
SELECT GENERATE_SERIES(1, 10, 2);归来整型序列,指定步长
1.2 归来浮点典型序列
此功效一致于归来整型序列,各别点是传入的不妨是带少量位的浮点典型数据,如次图所示:
SELECT GENERATE_SERIES(1.1, 10.9, 0.5);归来浮点典型序列,指定步长
1.3 归来功夫戳(timestamp)序列
此功效不妨经过指定开始,尽头和步长征三号个参数,归来一段功夫戳的序列数据,如次图所示:
SELECT GENERATE_SERIES('2022-01-01'::TIMESTAMP, '2022-01-31'::TIMESTAMP, '1 DAY') AS datum;归来功夫戳序列
须要提防的是:
必需同声指定三个参数,开始,尽头,步长;开始和尽头参数,必需是功夫戳典型(timestamp),即使传入的是日子典型,须要表露变换;步长不妨是钟点,秒钟,秒,天,礼拜,年等;日子典型数据操纵
咱们须要记取这一个操纵:日子 + 平头 = 日子,如底下例子所示:
date + integer → dateAdd a number of days to a datedate '2022-01-09' + 5 → 2022-01-14Case 1: 当月计划
Case 2: 跨月计划
底下咱们贯串GENERATE_SERIES 因变量实行怎样获得一个日子典型的序列;
开始:2022-01-01, 尽头:2022-01-31;这两个功夫点中央间隙了30天,经过代码实行如次:
SELECT '2022-01-01'::DATE + s.a AS datumFROM GENERATE_SERIES(0, 30) AS s(a);截止如次图所示:
经过GENERATE_SERIES因变量归来日子典型序列
这种计划的上风是:
归来日子典型序列,原因变量仅扶助传时髦间戳典型数据;不须要按日子功夫的Interval指定功夫间隙,将功夫间隙默许为1天。自设置因变量
经过上头的熟习,咱们仍旧不妨经过传入发端日子和间隙天数获得咱们想要的截止。然而即使交易上常常变幻发端日子和功夫间隙,咱们还须要连接的重写SQL语句。为了制止从新改写SQL语句,咱们将设置一个因变量“get_calendar”,并将“发端日子”(start_dt)和“功夫间隙”(days)做为参数字传送入,进而使咱们的截止和语句越发精巧。
代码如次所示:
CREATE OR REPLACE FUNCTION public.get_calendar(start_dt date,days integer) RETURNS TABLE(datum date) LANGUAGE 'sql'AS $BODY$SELECT start_dt + s.a AS datumFROM GENERATE_SERIES(0, days) AS s(a)GROUP BY s.aORDER BY 1;$BODY$;大略尝试一下,仍旧将‘2022-01-01’动作发端日子,功夫间隙树立为30天:
SELECT * FROM get_calendar('2022-01-01', 30);自设置因变量让代码越发精巧
完备代码实行
最后,咱们将经过PostgreSQL的洪量日子和字符串变换因变量,扩充咱们的自设置因变量“get_calendar”,获得一个完备的日历表,简直代码如次所示。
/* Author: Derek ZhuDate: 2022-01-08Purpose: Calendar table practice in PostgreSQL 14.1Description: Start date: 2022-01-01 Set days length in 2nd argument of 'Genarate_series' function */-- FUNCTION: public.get_calendar(date, integer)-- DROP FUNCTION IF EXISTS public.get_calendar(date, integer);CREATE OR REPLACE FUNCTION public.get_calendar(start_dt date,days integer) RETURNS TABLE(datum date, year numeric, month numeric, day_of_month numeric, week_of_year numeric, iso_day_of_week numeric, year_calendar_week text, day_of_year numeric, quarter_of_year numeric, quartal text, year_quartal text, day_name text, month_name text, year_month text, year_half integer, leap_year boolean, weekend text, cw_start date, cw_end date, month_start date, month_end date) LANGUAGE 'sql' COST 100 VOLATILE PARALLEL UNSAFE ROWS 1000AS $BODY$SELECT datum, EXTRACT(YEAR FROM datum) AS "year", EXTRACT(MONTH FROM datum) AS "month", EXTRACT(DAY FROM datum) AS day_of_month, EXTRACT(WEEK FROM datum) AS week_of_year, -- ISO 8601 day of the week numbering, The day of the week as Monday (1) to Sunday (7) EXTRACT(ISODOW FROM datum) AS iso_day_of_week, -- Standard Gregorian day of the week numbering, The day of the week as Sunday (0) to Saturday (6) -- EXTRACT(DOW FROM datum) AS day_of_week, -- ISO calendar year and week TO_CHAR(datum, 'iyyy/IW') AS year_calendar_week, EXTRACT(DOY FROM datum) AS day_of_year, EXTRACT(QUARTER FROM datum) AS quarter_of_year, 'Q' || TO_CHAR(datum, 'Q') AS quartal, TO_CHAR(datum, 'yyyy/"Q"Q') AS year_quartal, TO_CHAR(datum, 'TMDay') AS day_name, TO_CHAR(datum, 'TMMonth') AS month_name, TO_CHAR(datum, 'yyyy/mm') AS year_month, -- Half year CASE WHEN EXTRACT(MONTH FROM datum) < 7 THEN 1 ELSE 2 END AS year_half, -- Leap year CASE WHEN EXTRACT(YEAR FROM datum) % 4 = 0 THEN TRUE ELSE FALSE END AS leap_year, -- Weekend CASE WHEN EXTRACT(ISODOW FROM datum) in (6, 7) THEN 'Weekend' ELSE 'Weekday' END AS weekend, -- ISO start and end of the week of this date datum + (1 - EXTRACT(ISODOW FROM datum))::integer AS cw_start, datum + (7 - EXTRACT(ISODOW FROM datum))::integer AS cw_end, -- Start and end of the month of this date datum + (1 - EXTRACT(DAY FROM datum))::integer AS month_start, ((datum + (1 - EXTRACT(DAY FROM datum))::integer + '1 month'::interval)::date - '1 day'::interval)::DATE AS month_endFROM (SELECT start_dt + s.a AS datumFROM GENERATE_SERIES(0, days) AS s(a)GROUP BY s.a) AS calendarORDER BY 1;$BODY$;ALTER FUNCTION public.get_calendar(date, integer) OWNER TO postgres;获得2022年终年日历,如次所示:
SELECT * FROM get_calendar('2022-01-01', 364);2022 Calendar Table
经过文本编纂器查看截止,如次所示:
Calendar data in csv
经过Excel查看截止,如次所示:
Calendar data in excel
至此,咱们仍旧实行了一切功效;
归纳
经过PostgreSQL天生日历表重要有底下几个提防点:
ISO8601规范中,一个礼拜的天数为:Monday (1) ~ Sunday (7);领会并精巧运用GENERATE_SERIES因变量天生日子序列;养成模块化思想风气,将通用的数据操纵笼统为因变量或本领,不妨扩充运用范畴;与前天经过Python Pandas的案例一律,咱们最后也将处置计划?