选择数组中的任何值是否为列值的开头

时间:2017-06-12 10:46:08

标签: sql arrays postgresql postgresql-9.5

所以我从Python网络服务器获得了一个数组codes,我需要选择所有具有与这些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 || '%'这样的数组是不合法的,所以我怎么能这样做?

3 个答案:

答案 0 :(得分:2)

可能有更好的方法来做到这一点。但是一般概念对我来说是有意义的:如果项目的长度小于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

答案 1 :(得分:1)

您需要弄清楚如何将数组传递给查询。显然,您可以在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 || '%';

如果要返回匹配的模式,使用Postgres数组特别有用。

答案 2 :(得分:1)

这个小功能可以完成这项工作:

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

示例:

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)