使用连接条件更新另一个表的列中的匹配词

Mat*_*att 6 postgresql full-text-search pattern-matching update postgresql-9.4

我有 2 个看起来像这样的表:

表一:

CREATE TEMP TABLE table_a (
  Column_1 text,
  ID_number int
);
INSERT INTO table_a VALUES
  ('foo,bar,baz', 123),
  ('qux,quux,quuz',456),
  ('corge,grault,garply',789),
  ('qux,bar,grault', 101);
Run Code Online (Sandbox Code Playgroud)

表 B:

CREATE TEMP TABLE table_b (
  Column_1 text,
  Column_2 text,
  ID_number int
);
INSERT INTO table_b VALUES
  ('foo','baz',null),
  ('qux','quzz',null),
  ('corge','garply',null);
Run Code Online (Sandbox Code Playgroud)

我正在尝试从表 A 中的 ID_number 列复制值,其中表 B 的第 1 列和第 2 列中的值可以在表 A 的第 1 列的同一行中找到。

这是我在想的事情:

UPDATE table_b AS B 
SET id_number = A.id_number 
FROM table_a AS A 
WHERE A.column_1 LIKE B.column_1
  AND A.column_1 LIKE B.column_2
Run Code Online (Sandbox Code Playgroud)

.. 但显然这行不通。

如何将其转换为正确的查询?

附加信息

table_a.Column_1 包含英国地址,例如:

'47 BOWERS PLACE, GREAT YARMOUTH, NORFOLK, NR20 4AN'
Run Code Online (Sandbox Code Playgroud)

table_b我有地址的第一行Column_1(so, '47 BOWERS PLACE') 和邮政编码 ( 'NR20 4AN') 在Column_2.

我认为最好简化事情,但也许实际数据在这种情况下有一些相关性。

table_a有大约 3000 万个地址。table_b有大约 60k 行。

性能是相关的,运行得越快越好,并且将来可能会重复。

Eva*_*oll 7

这里的关键是Column_1,代表 JOIN 的三个可能值。所以你想要使用的是string_to_array()(只要这些值是逗号分隔的并且本身不能包含逗号)。

运行这个查询,

SELECT id_number, string_to_array(column_1, ',') AS column_1
FROM table_a;
 id_number |       column_1        
-----------+-----------------------
       123 | {foo,bar,baz}
       456 | {qux,quux,quuz}
       789 | {corge,grault,garply}
       101 | {qux,bar,grault}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以运行我们的UPDATEusing = ANY()

UPDATE table_b
SET id_number = A.id_number
FROM (
  SELECT id_number, string_to_array(column_1, ',') AS column_1
  FROM table_a
) AS A
WHERE table_b.column_1 = ANY(A.column_1)
  AND table_b.column_2 = ANY(A.column_1);
Run Code Online (Sandbox Code Playgroud)

您也可以使用 <@

WHERE ARRAY[table_b.column_1, table_b.column_2] <@ A.column_1;
Run Code Online (Sandbox Code Playgroud)

这甚至使它更紧凑一点..

UPDATE table_b
  SET id_number = A.id_number
FROM table_a AS A                              
  WHERE ARRAY[table_b.column_1, table_b.column_2] <@ string_to_array(A.column_1, ',');
Run Code Online (Sandbox Code Playgroud)


McN*_*ets 5

尝试这个:

update table_b
set id_number = (select id_number
                 from table_a
                 where table_a.Column_1 like '%' || table_b.Column_1 || '%'
                       OR table_a.Column_1 like '%' || table_b.Column_2 || '%'
                 limit 1)
;
Run Code Online (Sandbox Code Playgroud)

通过将 Column_1 转换为数组可以是另一种解决方案,但这很清楚。

请注意,我将搜索限制为 1 条记录,以防文本出现在 Table_A 的多个 column_1 中。

正如埃文卡罗尔在评论部分指出的那样,我会注意到这段代码更新了整个表格。

在这里检查:http : //rextester.com/MUL4593


Erw*_*ter 3

假设Postgres 9.6,性能相关,大表,由字符组成的“单词”,没有空格或标点符号,没有词干或停止词,没有短语,所有列NOT NULL

由索引支持的全文搜索应该是最快的解决方案之一:

UPDATE table_b b
SET    id_number = a.id_number 
FROM   table_a a
WHERE  to_tsvector('simple', a.column_1)
    @@ plainto_tsquery('simple', concat_ws(' ', b.column_1, b.column_2))
AND    b.id_number = a.id_number;  -- prevent empty UPDATEs
Run Code Online (Sandbox Code Playgroud)

具有匹配的表达式索引a.column_1

CREATE INDEX table_a_column_1_idx ON table_a USING GIN (to_tsvector('simple', column_1));
Run Code Online (Sandbox Code Playgroud)