我可以拥有无限多行的视图吗?我不想一次选择所有行,但是是否可以有一个表示重复的每周计划的视图,其中包含任何日期的行?
我有一个数据库,其中包含有关企业的信息,以及一周中不同日子的营业时间。他们的名字:
# 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 中)?或者视图甚至是做我想做的事情的方式?
更新
以下是有关我的表的更多详细信息。星期几保存为位,我使用位掩码选择适当的行,该位掩码在请求的一周的每一天都有一个位移位。以机智:
公司表:
# \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
子句中而不是在括号内传递参数来调用我已经拥有的函数。