如何检查子字符串是否在 Postgres 中的任何数组值中?

How to check if a substring is in any array value in Postgres?

所以我有以下用例:

我有三个 street_anumber_aaddress_list 类型 varchar 的值,如下所示:

address_a = 'Main Street'
number_a = '4'
address_list = 'Lower Street 6;Main Street 3,4,5'

现在我想 return 一个 TRUE 当我检查 street_anumber_a (Main Street 4) 的连接字符串时,因为它是一部分address_list 个。我希望以下内容会起作用:

SELECT 
    lower(REPLACE(street_a, ' ', '')) || '%,' || number_a || ',%' 
    LIKE ANY 
    (string_to_array(lower(REPLACE(address_list, ' ','')), ';'))

但是,LIKE 语句中的 % 符号仅在检查右侧时应用。当在左侧时,它们只是连接到字符串...

编辑

并且由于其他情况,例如

address_list = 'Main Street 1,2;Lower Street 4'

我做不到

SELECT 
    lower(REPLACE(address_list, ' ',''))
    LIKE
    lower(REPLACE(street_a, ' ', '')) || '%' || number_a || '%'  

有没有办法 return TRUE 我的情况?

address_list = 'Lower Street 6;Main Street 3,4,5'

在SQL中存储这样的列表是非常低效和复杂的。相反,将每个地址存储在它自己的行中。

create table addresses (
  address text not null
);

insert into addresses values
  ('Lower Street 6'), ('Main Street 3'), ('Main Street 4'), ('Main Street 5');

现在很简单select。

select 1
from addresses
where lower(address) = lower(street_a) || ' ' || number_a

您可以将 lower(address) 编入索引以快速 运行 并避免重复。

create unique index lower_case_address ON addresses ((lower(address)));

Demonstration.

我想说这不是存储地址或进行查找的最佳方式。地址有很多复杂性,这种方法不太适合。我建议不要走这条路。但是,如果您被迫这样做,那么我认为使用 regular expression 可能比 LIKE 表达式更好。

注意:我不是在解决街道或号码可能包含应该转义的字符或许多其他情况的可能性,但这段代码“可以”在某些情况下工作。

CREATE OR REPLACE FUNCTION address_match(street_a text, number_a text, address_list text) RETURNS BOOLEAN LANGUAGE plpgsql AS     
$$ 
declare
  pattern text := replace(street_a, ' ', '') || '(([0-9]+,)*)' || number_a || '(,.*)?$'; 
  result bool;
begin
  with a as (SELECT unnest(string_to_array(replace(address_list,  ' ', ''), ';')) as address) 
  select exists(select a.address from a where a.address ~* pattern) into result;
  return result;
end;
$$;

一些快速测试场景...

postgres=# select address_match('Main Street', '3', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 t
(1 row)

postgres=# select address_match('Main Street', '4', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 t
(1 row)

postgres=# select address_match('Main Street', '5', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 t
(1 row)

postgres=# select address_match('maiN StreeT', '3', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 t
(1 row)

postgres=# select address_match('Main Street', '33', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 f
(1 row)

postgres=# select address_match('Main Street', '45', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 f
(1 row)

postgres=# select address_match('maiN StreeT', '1', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 f
(1 row)

postgres=# select address_match('Lower    StreeT', '6', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 t
(1 row)

postgres=# select address_match('Lower    StreeT', '3', 'Lower Street 6;Main Street 3,4,5');
 address_match 
---------------
 f
(1 row)