行数が無限のビューを作成できますか? 一度にすべての行を選択したくありませんが、任意の日付の行を含む毎週の繰り返しスケジュールを表すビューを持つことは可能ですか?
私は、企業、曜日ごとの営業時間に関する情報を含むデータベースを持っています。彼らの名前:
# SELECT company_name FROM company;
company_name
--------------------
Acme, Inc.
Amalgamated
...
(47 rows)
毎週のスケジュール:
# SELECT days, open_time, close_time
FROM hours JOIN company USING(company_id)
WHERE company_name='Acme, Inc.';
days | open_time | close_time
---------+-----------+-----------
1111100 | 08:30:00 | 17:00:00
0000010 | 09:00:00 | 12:30:00
表示されていない別のテーブルには、休業日があります。
したがって、特定の日付を引数として取り、各会社の営業時間を返すストアド プロシージャの形式で、ユーザー定義関数を簡単に作成できます。
SELECT company_name,open_time,close_time FROM schedule_for(current_date);
しかし、次のように、SQL 互換のホスト言語ライブラリとのインターフェイスに問題がないように、テーブル クエリとして実行したいと考えています。
SELECT company_name, open_time, close_time
FROM schedule_view
WHERE business_date=current_date;
リレーショナル データベース理論によると、テーブル (リレーション) は、各主キーから行 (タプル) への一意のマッピングであるという意味で関数です。明らかWHERE
に、上記のクエリの句が省略された場合、テーブル (ビュー) の行数が無限になり、これは実際的な問題になります。WHERE
しかし、行数を制限する句なしでそのようなビューをクエリしないことに同意したいと思います。
そのようなビューを (PostgreSQL で) どのように作成できますか? それとも、ビューは私がやりたいことをする方法でもありますか?
アップデート
ここに私のテーブルに関するいくつかの詳細があります。曜日はビットとして保存され、要求された曜日ごとに 1 ビットずつシフトされるビット マスクを使用して、適切な行を選択します。ウィット:
会社のテーブル:
# \d company
Table "company"
Column | Type | Modifiers
----------------+------------------------+-----------
company_id | smallint | not null
company_name | character varying(128) | not null
timezone | timezone | not null
時間表:
# \d hours
Table "hours"
Column | Type | Modifiers
------------+------------------------+-----------
company_id | smallint | not null
days | bit(7) | not null
open_time | time without time zone | not null
close_time | time without time zone | not null
休日テーブル:
# \d holiday
Table "holiday"
Column | Type | Modifiers
---------------+----------+-----------
company_id | smallint | not null
month_of_year | smallint | not null
day_of_month | smallint | not null
私が現在持っている機能は、(呼び出し以外に)私が望むことを次のように定義されています。
CREATE FUNCTION schedule_for(requested_date date)
RETURNS table(company_name text, open_time timestamptz, close_time timestamptz)
AS $$
WITH field AS (
/* shift the mask as many bits as the requested day of the week */
SELECT B'1000000' >> (to_char(requested_date,'ID')::int -1) AS day_of_week,
to_char(requested_date, 'MM')::int AS month_of_year,
to_char(requested_date, 'DD')::int AS day_of_month
)
SELECT company_name,
(requested_date+open_time) AT TIME ZONE timezone AS open_time,
(requested_date+close_time) AT TIME ZONE timezone AS close_time
FROM hours INNER JOIN company USING (company_id)
CROSS JOIN field
CROSS JOIN holiday
/* if the bit-mask anded with the DOW is the DOW */
WHERE (hours.days & field.day_of_week) = field.day_of_week
AND NOT EXISTS (SELECT 1
FROM holiday h
WHERE h.company_id = hours.company_id
AND field.month_of_year = h.month_of_year
AND field.day_of_month = h.day_of_month);
$$
LANGUAGE SQL;
繰り返しますが、私の目標は、これを行うことで今日のスケジュールを取得できるようにすることです。
SELECT open_time, close_time FROM schedule_view
wHERE company='Acme,Inc.' AND requested_date=CURRENT_DATE;
また、次のようにして、任意の日付のスケジュールを取得することもできます。
SELECT open_time, close_time FROM schedule_view
WHERE company='Acme, Inc.' AND requested_date=CAST ('2013-11-01' AS date);
これには、ここで参照されているビューを作成する必要があるとschedule_view
思いますが、それについては間違っているかもしれません。いずれにせよ、現在私が持っているユーザー定義関数にあるように、コマンドライン インターフェイスとクライアント言語データベース ライブラリで使用されないように、乱雑な SQL コードを隠しておきたいと考えています。
WHERE
つまり、括弧内ではなく句で引数を渡すことによって、既に持っている関数を呼び出したいだけです。