PostgreSQL搜索字符串列中的子字符串列表

时间:2019-12-12 16:04:51

标签: sql postgresql

我在postreSQL数据库中有下表(为简化起见已简化):

  | serverdate |           name | value 
  |-------------------------------------
0 | 2019-12-01 | A LOC 123 DISP | 1
1 | 2019-12-01 | B LOC 456 DISP | 2
2 | 2019-12-01 | C LOC 777 DISP | 0
3 | 2019-12-01 | D LOC 000 DISP | 10
4 | 2019-12-01 | A LOC 700 DISP | 123
5 | 2019-12-01 | F LOC 777 DISP | 8

名称列的类型为字符串。子字符串 LOC DISP 可以具有其他长度不同的值,但此问题无关。

问题:我想选择仅包含特定子字符串的行。有几个子字符串,以ARRAY的形式传递,格式如下:

['A_123', 'F_777'] # this is an example only

我想选择包含子字符串第一部分(由下划线'_'分隔)以及第二部分的所有行。在此示例中,使用上述数组,我应该获得第0行和第5行(因为这是在的两部分中唯一具有完全匹配项的行):

  | serverdate |           name | value 
  |-------------------------------------
0 | 2019-12-01 | A LOC 123 DISP | 1
5 | 2019-12-01 | F LOC 777 DISP | 8

第4行的子字符串的第一部分正确,而另一部分则没有,因此不应返回。第2行也一样(只有第二部分匹配)。

该查询如何完成?我对SQL比较陌生。

此查询是Python处理过程的一部分,因此我可以根据需要调整输入参数(子字符串数组),但是其行为必须与所描述的相同。

谢谢!

4 个答案:

答案 0 :(得分:1)

您是否尝试过使用regexp_replace和子查询?

SELECT * FROM 
  (SELECT serverdate, substring(name from 1 for 1)||'_'||
          regexp_replace(name, '\D*', '', 'g') AS name, value 
  FROM t) j 
WHERE name IN('A_123', 'F_777');

或使用CTE

WITH j AS (
SELECT serverdate, substring(name from 1 for 1)||'_'||
       regexp_replace(name, '\D*', '', 'g') AS name2, 
       value,name
FROM t 
) SELECT serverdate,name,value FROM j 
  WHERE name2 IN('A_123', 'F_777');


 serverdate |      name      | value 
------------+----------------+-------
 2019-12-01 | A LOC 123 DISP |     1
 2019-12-01 | F LOC 777 DISP |     8
(2 Zeilen)

答案 1 :(得分:1)

只需嵌套数组并使用like子句连接表

select
    *
from
    Table1
join 
(
    select 
        '%'||replace(unnest, '_', '%')||'%' pat 
    from 
        unnest(array['A_123', 'F_777'])
) pat_table on "name" like "pat"

只需将unnest(array['A_123', 'F_777'])替换为unnest(string_to_array(str_variable, ','))

答案 2 :(得分:1)

感谢您的回答! Larry B的解决方案使我遇到了一个错误,但这是由外部因素引起的(我使用由我公司开发的内部工具运行查询,当使用通配符时,它引发了错误。已经联系了支持团队),所以我无法对其进行正确的测试。

吉姆·琼斯(Jim Jones)的解决方案似乎是另一种选择,但我发现在某些情况下, name 字段中的值看起来像这样(在编写问题时没有注意到它,因为它罕见的情况):

ABC LOC 123 DISP

因此,我对解决方案进行了一些修改,以便在用''字符分割名称时抓住名称的第一部分。

(TLDR:名称的第一个子字符串可以是任意长度,但始终在开头)

我的解决方法是:

SELECT * FROM 
  (SELECT serverdate, split_part(name, ' ', 1)||'_'||
          regexp_replace(name, '\D*', '', 'g') AS name, value 
  FROM t) j 
WHERE name IN('A_123', 'F_777');

答案 3 :(得分:0)

split_part(name,'_',1) + '_' + split_part(name,'_',3) as name

这是查询的细分:A + _ + 123 = A_123