次のような2つのテーブルがあります。
表A:
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);
表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);
テーブルAの列1と2の値がテーブルAの列1の同じ行にあるテーブルAのID_number列から値をコピーしようとしています。
これは私が考えていたようなものです:
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
..しかし、明らかにこれは機能しません。
これを適切なクエリに変換するにはどうすればよいですか?
追加情報
table_a.Column_1
には、英国の住所が含まれています。次に例を示します。
'47 BOWERS PLACE, GREAT YARMOUTH, NORFOLK, NR20 4AN'
table_b
には、Column_1
に住所の最初の行('47 BOWERS PLACE'
)があり、'NR20 4AN'
に郵便番号(Column_2
)があります。
物事を単純化するのが最善だと思いましたが、実際のデータはこの状況である程度の関連性があります。
table_a
には約3,000万のアドレスがあります。 table_b
には約60k行あります。
パフォーマンスは重要であり、これが高速で実行されるほど優れており、今後も繰り返される可能性があります。
仮定Postgres 9.6、パフォーマンスに関連、大きなテーブル、文字で構成される「単語」、空白なしまたは句読点、ステミングまたはストップワードなし、フレーズなし、すべての列NOT NULL
。
全文検索 インデックスに裏打ちされたものは、最速のソリューションの1つです:
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
a.column_1
に一致する式のインデックスがある場合:
CREATE INDEX table_a_column_1_idx ON table_a USING GIN (to_tsvector('simple', column_1));
ここで重要なのは、_Column_1
_がJOINの3つの可能な値を表すことです。したがって、使用したいのは 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}
_
これで、_ = ANY()
を使用してUPDATE
を実行できます。
_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);
_
または、 _<@
_ を使用することもできます
_WHERE ARRAY[table_b.column_1, table_b.column_2] <@ A.column_1;
_
これにより、さらにコンパクトになります。
_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, ',');
_
これを試して:
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)
;
Column_1を配列に変換することで別の解決策になる可能性もありますが、これは非常に明確です。
テキストがTable_Aの複数のcolumn_1に表示される場合に備えて、検索を1レコードに制限していることに注意してください。
Evan Carroll がコメントセクションで指摘したように、このコードはテーブル全体を更新することに注意します。
ここで確認してください: http://rextester.com/MUL459