如何使用动态正则表达式匹配 Postgres 中的值

Posted

技术标签:

【中文标题】如何使用动态正则表达式匹配 Postgres 中的值【英文标题】:How to use dynamic regex to match value in Postgres 【发布时间】:2021-08-31 15:52:35 【问题描述】:

总结:我有两个表我想从中获取信息:family_values (family_name, item_regex)product_ids (product_id) 以便能够在第三个中更新属性 family_name。 这里的计划是从小的family_values 表中获取一个json 数组,并使用列值item_regexproduct_id 中的每一行进行测试匹配product_ids

更多详细信息:将静态数据从 CSV 导入到 orders 的表中。但是,在评估商品成本和市场价值时,我需要不断地根据 product_id 上的前缀正则表达式(来自 family_values 的 item_regex)匹配来确定族。 在客户端上是这样的:

const families =  
FOOBAR: 'Big Ogre',
FOOBA: 'Wood Elf',
FOO: 'Valkyrie'
;
// And to find family, and subsequently COGs and Market Value:
const findFamily = product_id => Object.keys(families).find(f => new RegExp('^' + f).test(product_id));

这对客户来说是一个巨大的打击,所以我在 PG 中创建了一个family_values 表来包含一个代表:family_name、item_regex、cogs、market_value。 然后,product_ids 有一个仅包含应用程序关心的产品的列表(数以百万计)。这实际上与“on before”插入触发器一起使用,以忽略任何不在 product_ids 视图中的 CSV 条目。所以,我想在那之后 product_ids 视图可以被排除在等式之外,因为orders,在插入只读数据之后,有自己匹配的 product_id。它没有family_name,所以我仍然有确定客户端的问题。

伪代码:使用family_values 正则表达式匹配orders.product_id 中的family_name 更新订单的family 列 OR 使用新的 family 列更新 product_ids 表,并将其与现有的 on insert 触发器一起使用(现在用于左填充零和规范化数据)。现在我认为这可能只是建议的更新,但对于 PG 中的正则表达式并不是很好。我是PG新手。

问题:但是,我在执行我认为类似于 JS 数组查找操作的操作时遇到了问题。 family_values 已在 item_regex 上进行排序,以便最严格的匹配位于顶部,因此首先找到。

例如,通过排序我们有:

family_values_array = [
"family_name": "Big Ogre", "item_regex": "FOOBAR", 
"family_name": "Wood Elf", "item_regex": "FOOBA", 
"family_name": "Valkyrie", "item_regex": "FOO"]

因此,product_id^FOOBA 的比较将产生家庭“木精灵”。

解决方案: 我最终使用的解决方案是简单地使用 concat 写出前面锚定的正则表达式。最后就这么简单。我缺少的关键是:

select * into family_value_row from iol.family_values 
where lvl3_id = product_row.lvl3_id and product_row.product_id 
like concat(item_regex, '%') limit 1;

整个函数:

create or replace function iol.populate_families () returns void as $$
declare
    product_row record;
    family_value_row record;
begin
for product_row in
    select product_id, lvl3_id from iol.products
loop
    -- family_name is what we want after finding the BEST match fr a product_id against item_regex
    select * into family_value_row from iol.family_values 
      where lvl3_id = product_row.lvl3_id and product_row.product_id like concat(item_regex, '%') limit 1;
    -- update family_name and value columns
    update iol.products set 
      family_name = family_value_row.family_name, 
      cog_cents = family_value_row.cog_cents, 
      market_value_cents = family_value_row.market_value_cents
        where product_id = product_row.product_id;
end loop;
end;
$$
LANGUAGE plpgsql;

【问题讨论】:

根据您的描述,我想说您既不需要循环也不需要 PL/pgSQL。很可能这可以使用将三个表放在一起的单个 UPDATE 语句轻松完成。但如果没有更多细节,这真的很难说。 我会添加更多细节。谢谢。 【参考方案1】:

使用上面更新的 concat:

select * into family_value_row from iol.family_values 
where lvl3_id = product_row.lvl3_id and product_row.product_id 
like concat(item_regex, '%') limit 1;

【讨论】:

以上是关于如何使用动态正则表达式匹配 Postgres 中的值的主要内容,如果未能解决你的问题,请参考以下文章

Postgres中的正则表达式查找和替换

postgres 与正则表达式匹配

匹配h2 / postgres中的文字百分比?

如何在红移中进行动态正则表达式匹配?

在 postgres 中匹配 regexp_replace 中的 2 个条件

多正则表达式匹配 (Multiple Regular Expression Matching) 中的动态 DFA 算法