Select 如果数组中的任何值是列值的开头

Select if any value in an array is the beginning of a column's value

所以我从 Python 网络服务器得到了一个数组 codes,我需要 select 具有与其中任何一个匹配的列的所有行 codes:

SELECT a.*
FROM a
LEFT JOIN b ON b.code = a.bcode
WHERE b.code = ANY(codes);

但问题是,这些代码可能只是部分代码,只是代码的开头。因此,虽然完整的代码总是 5 个字母长(它们存储为字符串),但我收到的代码数组可能类似于 ['01', '4332', '34443']。如果 b 中的一行具有 '01233' 作为列的值,它应该与数组中的 '01' 匹配。请注意,它不会匹配到 '23',它应该只匹配到开头。

本质上我想要这样的东西:

SELECT a.*
FROM a
LEFT JOIN b ON b.code = a.bcode
WHERE b.code LIKE ANY(codes || '%');

显然像 codes || '%' 那样附加到数组是不合法的,那么我该怎么做呢?

您需要弄清楚如何将数组传递到查询中。显然,您可以在 Python 中构造一个 WHERE 子句并执行类似以下操作:

where code like '01%', or
      code like '4332%' or 
      code like '34443%'

您可以将其缩短为正则表达式:

where code ~ '^(01|4332|34443)'

或者,您可以将其作为 Postgres 数组传入,执行如下操作:

select v.*, p2.pat
from (values ('a'), ('abc'), ('abcd'), ('bacd')) v(x) cross join
     (select array['a', 'b'] as pat) p, lateral
     unnest(p.pat) p2(pat)
where v.x like p2.pat || '%';

如果您想 return 匹配的模式,使用 Postgres 数组特别有用。

可能有更好的方法来做到这一点。但一般概念对我来说很有意义:如果项目的长度小于 5,则更改数组以附加 % 字符。

SELECT [...]
FROM [...] x
WHERE x.code LIKE ANY(ARRAY(
    SELECT CASE WHEN LENGTH(u) < 5 THEN u || '%' ELSE u END
    FROM UNNEST([your array]) u)
);

工作示例:

SELECT g
FROM generate_series(9995, 10005) g
WHERE g::TEXT LIKE ANY(ARRAY(
    SELECT CASE WHEN LENGTH(u) < 5 THEN u || '%' ELSE u END
    FROM UNNEST(ARRAY['999','10005']) u)
);

结果:

9995
9996
9997
9998
9999
10005

这个小函数可以完成这项工作:

create or replace function array_for_like(text[])
returns text[] language sql as $$
    select string_to_array(concat(array_to_string(, '%,'), '%'), ',')
$$;

示例:

with my_table(code) as (
values
    ('10001'),
    ('10002'),
    ('20001'),
    ('20002'),
    ('30001')
)

select *
from my_table
where code like any(array_for_like(array['10', '30']))

 code  
-------
 10001
 10002
 30001
(3 rows)