我需要能够找到一个基于数字范围的行,并另存为文本字段。例如,周二的字段看起来像540-1020。如果要搜索900,我想检索此行。到目前为止,
SELECT string_to_array(tuesday, '-')
FROM coverage
WHERE 900 IN string_to_array(tuesday, '-')
其中string_to_array(星期二,'-')打印出来的像{540,1020}。如何将其转换为可选的整数范围?
答案 0 :(得分:1)
使用range。
SELECT string_to_array(tuesday, '-')
FROM coverage
WHERE 900 <@ int4range(split_part(tuesday, '-', 1)::int4, split_part(tuesday, '-', 2)::int4, '[]');
最后一个参数[]
表示'100-900'
匹配的范围。您还可以进行专有的上限,例如[)
(请注意右边的括号),其中'100-900'
将不匹配,因为该上限编号不包括在匹配编号集中。
为了在表变大时提高查询速度,可以添加GIST函数索引。
CREATE INDEX tuesday_range_idx ON coverage
USING GIST (int4range(split_part(tuesday, '-', 1)::int4, split_part(tuesday, '-', 2)::int4, '[]'));
这暴露了数据模型中的一些弱点。通过将每一天作为一列,您必须为每一列创建一个单独的功能索引。每次运行时,您还必须将文本解析为数组。通常,您希望表中的数据与您访问数据的方式匹配,而不是序列化的形式。
代替
CREATE TABLE coverage (
id serial PRIMARY KEY,
year smallint, -- tracking by week
week_num smallint, -- for example
sunday varchar,
monday varchar,
tuesday varchar,
wednesday varchar,
thursday varchar,
friday varchar,
saturday varchar
);
为什么不喜欢
CREATE TABLE coverage (
id serial PRIMARY KEY,
day date NOT NULL UNIQUE,
daily_data int4range NOT NULL
);
INSERT INTO coverage (day, daily_data)
VALUES ('2020-06-02', '[540,1020]');
然后您的搜索就像
SELECT daily_data
FROM coverage
WHERE extract(DOW FROM day) = 2 -- Tuesday (Sunday is 0, Saturday is 6)
AND 900 <@ daily_data;
您可以为日期,日期(在我的示例中已经是唯一的索引),星期,月份,年份等的每日功能索引创建每日数据范围的索引。
或者,如果您绝对希望从SELECT
返回一个数组
SELECT ARRAY[lower(daily_data), upper(daily_data)]
FROM coverage
WHERE extract(DOW FROM day) = 2 -- Tuesday (Sunday is 0, Saturday is 6)
AND 900 <@ daily_data;