如何使用LIKE运算符在数组中搜索

时间:2019-04-02 17:01:44

标签: arrays postgresql database-design sequelize.js string-matching

 id |   name   |          ipAddress           
----+----------+-------------------------
  1 | testname | {192.168.1.60,192.168.1.65}

我想用ipAddress搜索LIKE。我尝试过:

{'$mac_ip_addresses.ip_address$': { [OP.contains]: [searchItem]}},

这也是:

{'$mac_ip_addresses.ip_address$': { [OP.Like] : { [OP.any]: [searchItem]}}},

ipAddress的数据类型为text[]。我想用ipAddressLIKE中搜索。 searchItem包含需要在ipAddress字段中搜索的IP,因此我想使用LIKE在数组中搜索。

2 个答案:

答案 0 :(得分:1)

我不知道Sequelize,但是我可以从postgres那里回答。

在PostgreSQL中的数组内搜索模式没有短语法。

如果要分别检查每个数组元素的模式,则需要使用unnest展开数组:

SELECT id, name, ipaddress
FROM testing
WHERE EXISTS (
  SELECT 1 FROM unnest(ipaddress) AS ip
  WHERE ip LIKE '8.8.8.%'
);

如果经常以这种方式搜索数组,则最好以规范化形式存储数据。

但是,对于基于相等的搜索(请参见@>和其他运算符here),有一种简短的语法(加上GIN索引支持)。

SELECT id, name, ipaddress
FROM testing
WHERE ipaddress @> ARRAY['8.8.8.8'];

答案 1 :(得分:1)

你问什么

~~ 是内部用于实现SQL LIKE的运算符。它没有commutator-没有操作符可以左右切换操作符。 这就是您尝试使用ANY construct left 模式的方式所需要的。相关:

不过,您可以create the operator,这很简单:

CREATE OR REPLACE FUNCTION reverse_like (text, text)
  RETURNS boolean LANGUAGE sql IMMUTABLE PARALLEL SAFE AS
'SELECT $2 LIKE $1';

CREATE OPERATOR <~~ (function = reverse_like, leftarg = text, rightarg = text);

灵感来自Jeff Janes的想法:

然后您的查询可以在运算符的左侧具有 pattern

SELECT *
FROM   mac_ip_addresses
WHERE  '192.168.2%.255' <~~ ANY (ipaddress);

EXISTS表达式demonstrated by filiprem简单但 ,。

然后,对于大表,这两个查询都非常慢,因为两个查询都不能使用索引。具有n:1表且每个表包含一个IP的规范化DB设计将允许这样做。它也将占用磁盘空间的几倍。不过,更清洁的实施方式...

虽然仍停留在当前的设计中,但是仍然有一种方法:在数组的文本表示形式上创建三字母组GIN索引,并向查询中另外添加一个冗余的“可精化”谓词。困惑?这是食谱:

首先,三字母组合索引?如果您不熟悉,请阅读以下内容:

text[]textarray_to_string()的转换都是不可变的。但是我们需要一个表达式索引。长话短说,使用不可变的包装函数伪造它:

CREATE OR REPLACE FUNCTION f_textarr2text(text[]) 
  RETURNS text LANGUAGE sql IMMUTABLE AS $$SELECT array_to_string($1, ',')$$;

CREATE INDEX iparr_trigram_idx ON iparr
USING gin (f_textarr2text(iparr) gin_trgm_ops);

有关长话的答案(以及为什么这样比较安全):

然后您的查询可以是:

SELECT *
FROM   mac_ip_addresses
WHERE  NOT ('192.168.9%.255' <~~ ANY (ipaddress))
AND    f_textarr2text(ipaddress) LIKE '192.168.9%.255';  -- logically redundant

添加的谓词在逻辑上是多余的,但可以利用trigram索引的功能。
快很多 用于大型桌子。还是更快一点:

SELECT *
FROM   mac_ip_addresses
WHERE  EXISTS (SELECT FROM unnest(ipaddress) ip WHERE ip LIKE '192.168.9%.255')
AND    f_textarr2text(ipaddress) LIKE '192.168.9%.255';

但是那是次要的。

db <>提琴here

我很感兴趣地回答了所问的问题。公众可能会感兴趣。不过,很可能不是您所需的

需要

  

我想用ipAddressLIKE中进行搜索。 searchItem包含需要在ipAddress字段中搜索的IP,因此我想使用LIKE在数组中搜索。

那应该读为:

“我想在数组searchItem中搜索给定的IP地址(ipAddress)。我的第一个想法是使用LIKE ...”

嗯,LIKE用于模式匹配。要在数组中查找完整 IP地址,这是错误的工具。 filiprem's second query和数组运算符是一条路。可能足够好。

使用built-in data type cidr代替text会更好。而且,附加的ip4r模块的ip4数据类型会更好。结合了示范的标准数组运算符。

最后,就性能而言,将IPv4地址转换为integer并与附加的inrarray module一起使用应该是出色的。