将包含列表的记录值与 Postgres 中的列值进行比较

Posted

技术标签:

【中文标题】将包含列表的记录值与 Postgres 中的列值进行比较【英文标题】:Compare a record value containing a list with column values in Postgres 【发布时间】:2021-02-01 20:50:57 【问题描述】:

我需要编写一个选择语句,该语句必须使用一个列值将两个表链接在一起,该列值包含一个由“,”分隔的项目列表,以及一个包含每个项目单独列出的列,也可以使用过滤结果那些相同的列。示例:

tbl_requests
requestid | requesteditems
1234567   | laptop,monitor,mouse
1234568   | laptop,dock
1234569   | monitor,keyboard,mouse
1234570   | monitor,dock,keyboard

tbl_storage
storageid | item
123       | laptop
123       | monitor
123       | mouse
123       | keyboard
154       | laptop
154       | dock

我无法控制如何将数据插入到请求表中。无论如何,我需要一个 select 语句来返回每个 requestid 和一个包含该请求的所有请求项的 storageid。如果没有 storagid 与所有请求的项目相关联,则该请求将被忽略。又名:

Result Table
requestid | storageid
1234567   | 123
1234568   | 154
1234569   | 123

不应包含 1234570,因为不是存储 ID 与所有请求的项目相关联。

据我所知,我可以使用 unnest 链接两个表,如下所示:

select distinct on (r.requestid) r.request, s.storageid from tbl_requests r, unnest(string_to_array(r.requesteditems, ',')) r(items)
join tbl_storage s on s.item=r.items

这让我很接近,但结果可能会有所不同,因为请求 1234568 可能会返回 123 或 154 作为 storageid,因为列出的第一项是笔记本电脑,这两个 storageid 都有与笔记本电脑关联的记录。此外,请求 1234570 将返回 storageid 123,因为该存储 id 确实有与之关联的监视器。

是否可以在上述查询中添加条件以确保返回的唯一请求是那些与requesteditem 中列出的每个项目相关联的storageid 的请求;还是我做错了?

【问题讨论】:

Is adding the ‘tbl’ prefix to table names really a problem? 【参考方案1】:

您可以将所有存储项聚合到一个数组中,将请求项转换为适当的数组,然后加入这些数组:

with storage as (
  select storageid, array_agg(item) items
  from tbl_storage
  group by storageid 
), requests as (
  select requestid, string_to_array(requesteditems,',') as items
  from tbl_requests
)
select r.requestid, s.storageid
from requests r
  join storage s on s.items @> r.items 

如果存储项 (s.items) 包含数组中具有请求项的所有元素,则表达式 s.items @> r.items 为真。

Online example

【讨论】:

空格是错字。幸运的是,我可以确认项目列表没有空格,至少目前是这样;但如果来源碰巧改变了他们管理数据的方式,我将不得不记住这一点。 @tmattson: 那么你应该使用string_to_array,因为它比正则表达式更快 尝试了这种方法,到目前为止一切顺利。我遇到的唯一问题是 array_agg 创建了一个字符可变数组,而 string_to_array 创建了一个文本数组。通过将 string_to_array 类型转换为字符变化来轻松修复:“string_to_array(requesteditems,',')::character varying[]”

以上是关于将包含列表的记录值与 Postgres 中的列值进行比较的主要内容,如果未能解决你的问题,请参考以下文章

当列表值与Pyspark数据帧中的列值的子字符串匹配时,填充新列

如何在带有 Postgres 的动态框架中使用窗口函数中的列值?

R - 如果列值与字符向量中的任何值匹配,则返回它旁边的列 [重复]

如何将逗号分隔的列值与另一个表作为行连接

MySQL索引简介

按 R 中的列值过滤列表中的每个数据框