如何确定范围列表是否包含指定的整数

How determine if range list contains specified integer

产品类型 table 包含产品类型。一些 ID 可能会丢失:

create table artliik (liiginrlki char(3) primary key);
insert into artliik values('1');
insert into artliik values('3');
insert into artliik values('4');
...
insert into artliik values('999');

属性 table 包含以逗号分隔的类型列表。

create table strings ( id char(100) primary key, kirjeldLku chr(200) );
insert into strings values ('item1', '1,4-5' );
insert into strings values ('item2', '1,2,3,6-9,23-44,45' );

类型可以指定为单个整数,e.q 1,2,3 或范围如 6-9 或 23-44 列表可以同时包含它们。

如何获取给定类型的所有属性。 查询

select id 
from artliik
join strings on ','||trim(strings.kirjeldLku)||',' like '%,'||trim(artliik.liiginrlki)||',%' 

returns 仅限单个整数列表的日期。 如何更改 join 以便也返回列表中的类型范围,如 6-9? 当量。 f 列表包含 6-9,类型 6、7、8 和 9 应包含在报告中。

使用 Postgres 13。

我建议使用类似于 unnest 的辅助函数来支持范围。

更正函数

create or replace function unnest_ranges(s text)
returns setof text language sql immutable as
$$
 with t(x) as (select unnest(string_to_array(s, ',')))
 select generate_series
 (
   split_part(x, '-', 1)::int, 
   case when x ~ '-' then split_part(x, '-', 2)::int else x::int end,
   1
 )::text
 from t;
$$;

然后你可以'normalize'tablestrings加入。

select * 
from artliik a 
join (select id, unnest_ranges(kirjeldLku) from strings) as t(id, v)
on a.liiginrlki = v;

函数定义的使用当然是可选的。我更喜欢它,因为它的功能是通用的和可重用的。

dbfiddle.uk demo 仅适用于 pg14,因为只有 pg14 具有多范围数据类型。但可自定义的 icu 整理在 pg13 中有效。
整理文档:https://www.postgresql.org/docs/current/collation.html


想法:创建一个多范围文本数据类型,它将根据数值对数值进行排序。像 'A-21' < 'A-123'.

CREATE COLLATION testcoll_numeric (
    provider = icu,
    locale = '@colNumeric=yes'
);

CREATE TYPE textrange AS RANGE (
    subtype = text,
    multirange_type_name = mulitrange_of_text,
    COLLATION = testcoll_numeric
);

所以

SELECT
    mulitrange_of_text (textrange ('1'::text, '11'::text)) @> '9'::text AS contain_9;

应该return正确.

artliik table 结构保持不变,但字符串 table 需要稍作更改。

CREATE temp TABLE strings (
    id text PRIMARY KEY,
    kirjeldLku mulitrange_of_text
);

然后查询:

SELECT DISTINCT
    strings.id
FROM
    artliik,
    strings
WHERE
    strings.kirjeldLku @> liiginrlki::text
ORDER BY
    1;