创建一个视图,其中包含一个 table 中的所有记录,这些记录与另一个 table 中的逗号分隔字段内容相匹配

Creating a view that contains all records from one table, that match the comma separated field content in another table

我有两个表 au_postcodes 和组。

  1. Table groups 包含一个名为 PostCodeFootPrint 的字段 包含构成足迹的邮政编码集。
  2. Table au_postcodes 包含一个名为 poa_code 的字段 包含一个邮政编码。

groups.PostCodeFootPrint 中的记录如下:

PostCodeFootPrint
2529,2530,2533,2534,2535,2536,2537,2538,2539,2540,2541,2575,2576,2577,2580
2640
3844
2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2079, 2080, 2081, 2082, 2083, 2119, 2120, 2126, 2158, 2159
2848, 2849, 2850, 2852

有些记录只有一个邮政编码,有些记录有多个,用“,”或“,”(逗号和 space)分隔。

au_postcode.poa_code中的记录如下:

poa_code
2090
2092
2093
829
830
836
2080
2081

单一邮政编码(始终)。

objective 是:

从au_postcode获取所有记录,其中poa_code出现在groups.*PostCodeFootPrint中查看。

我试过了:

SELECT
    au_postcodes.poa_code, 
    groups."NameOfGroup"
FROM
    groups,
    au_postcodes
WHERE
    groups."PostcodeFootprint" LIKE '%au_postcodes.poa_code%'

但运气不好

您可以为此使用正则表达式。看看这个fiddle:

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=739592ef262231722d783670b46bd7fa

我从 poa_code 和单词边界(以避免部分匹配)形成一个正则表达式并将其与 PostCodeFootPrint 进行比较。

select p.poa_code, g.PostCodeFootPrint
from groups g
join au_postcode p 
on g.PostCodeFootPrint ~ concat('\y', p.poa_code, '\y')

根据您的数据,这可能足够高效。我也相信在 postGres 中您可以访问数组数据类型,因此将 post 代码列表存储为数组可能更好。

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=ae24683952cb2b0f3832113375fbb55b

这里我将post代码列表存储为数组,然后使用ANY进行连接。

select p.poa_code, g.PostCodeFootPrint
from groups g
join au_postcode p 
on p.poa_code = any(g.PostCodeFootPrint);

在这两个 fiddle 中,我使用 explain 来显示查询的成本,虽然数组解决方案更昂贵,但我想它可能更容易维护。

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=7f16676825e10625b90eb62e8018d78e

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=e96e0fc463f46a7c467421b47683f42f

我在这个fiddle中将底层数据类型更改为整数,期望它可以降低成本,但没有,这让我觉得很奇怪。

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=521d6a7d0eb4c45471263214186e537e

可以使用 # 运算符降低查询成本(请参阅此处的最后一个查询:https://dbfiddle.uk/?rdbms=postgres_14&fiddle=edc9b07e9b22ee72f856e9234dbec4ba):

select p.poa_code, g.PostCodeFootPrint
from groups g
join au_postcode p 
on (g.PostCodeFootPrint # p.poa_code) > 0;

但它仍然比正则表达式贵。但是,我认为您可以重新安排 table 的设置方式并从根本上改变性能。查看 fiddle 中的第一个和第二个查询,我在其中获取足迹中的每个 post 代码并将其作为一行插入 table 中,连同它所在的组的标识符在:

select p.poa_code, g.which
from groups2 g
join au_postcode p 
on g.footprint = p.poa_code;

对此的解释计划表明查询成本显着下降(从 60752.50 下降到 517.20,或两个数量级)并且执行时间从 0.487 下降到 0.070。因此,可能值得考虑更改 table 结构。

由于 PostCodeFootPrint 的值由一个公共字符分隔,您可以轻松地从中创建一个数组。从那里使用 unnest 将数组元素转换为记录,然后加入 au_postcode:

SELECT * FROM au_postcode au
JOIN (SELECT trim(unnest(string_to_array(PostCodeFootPrint,','))) 
      FROM groups) fp (PostCodeFootPrint) ON fp.PostCodeFootPrint = au.poa_code;

演示:db<>fiddle