选择数字范围是否包含PostgreSQL中的数字

时间:2020-06-01 18:43:04

标签: postgresql

我需要能够找到一个基于数字范围的行,并另存为文本字段。例如,周二的字段看起来像540-1020。如果要搜索900,我想检索此行。到目前为止,

SELECT string_to_array(tuesday, '-')
FROM coverage 
WHERE 900 IN string_to_array(tuesday, '-')

其中string_to_array(星期二,'-')打印出来的像{540,1020}。如何将其转换为可选的整数范围?

1 个答案:

答案 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;
相关问题