SQLによるカレンダープログラム
Last modified: 2007/08/09 20:40:26
情報処理学会 夏のプログラミングシンポジウム「First Programming Languages プログラミング言語の実力と美学」の応援演説として、SQLを使ったカレンダープログラムを紹介しました。
基本的にZellerの公式を使って朔日の曜日を求め、各月の日数情報と組み合わせて整形して表示します。朔日から1ヶ月分を並べてしまうので、グレゴリオ暦への切り替え月は正常に表示されません。DBMSが持つ日付計算の機能を使ったり、PL/SQLの類の制御構造を使ってはつまらないので、SQLだけにしました。PostgreSQL-8.2.4を使っているので、PostgreSQLの制約に引きずられているかもしれません。create sequenceのmaxvalueやstartにサブクエリが使えると良かったのですが…。
drop table if exists result; create table result (Sun integer, Mon integer, Tue integer, Wed integer, Thu integer, Fri integer, Sat integer); drop table lastDays; create table lastDays (nDays integer[]); drop function if exists leap(integer); create function leap (integer) returns integer as $$ select case when (($1 % 4 = 0) and ($1 % 100 <>0) or ($1 % 400 = 0)) then 1 else 0 end; $$ language 'sql'; drop sequence if exists days; create sequence days minvalue -9 maxvalue 31 cycle; drop function if exists getYear (integer, integer); create function getYear (integer, integer) returns integer as $$ select case when (($1 = 1) or ($1 = 2)) then $2 - 1 else $2 end; $$ language 'sql'; drop function if exists getMonth (integer); create function getMonth (integer) returns integer as $$ select case when (($1 = 1) or ($1 = 2)) then $1 + 12 else $1 end; $$ language 'sql'; drop function if exists getDayOfWeek (integer, integer); create function getDayOfWeek (integer, integer) returns integer as $$ select (getYear($1,$2) + (getYear($1,$2)/4) - (getYear($1,$2)/100) + (getYear($1,$2)/400) + (13*getMonth($1)+8)/5 + 1)%7; $$ language 'sql'; drop function if exists getDay (integer); create function getDay (integer) returns bigint as $$ select case when (nextval('days') < 1) then 0 else (case when (currval('days') > $1) then 0 else currval('days') end) end; $$ language 'sql'; drop function if exists buildCal (integer, integer); create function buildCal (integer, integer) returns void as $$ insert into result values(getDay($2), getDay($2), getDay($2), getDay($2), getDay($2), getDay($2), getDay($2)); select case when ($1 > 1) then buildCal($1 - 1, $2) end; $$ language 'sql'; drop function if exists cal (integer, integer); create function cal (integer, integer) returns void as $$ delete from result; delete from lastDays; select setval('days', (select 0 - getDayOfWeek($1, $2))); insert into lastDays values ('{31,28,31,30,31,30,31,31,30,31,30,31}'); update lastDays set nDays[2] = (select nDays[2] from lastDays) + leap($2); select buildCal(6, (select nDays[$1] from lastDays)); $$ language 'sql'; select cal(8, 2007); select * from result;