2014-10-31 25 views
0

我有一張表,其中一列中的記錄與它們的寫法有所不同。 那麼如何找到這些並將相應的ID保存在一個新表中?SQL(postgres)中的哪個搜索策略用於查找類似的字符串

例如我在城市專欄中有以下記錄。

Id name 
1 berlin 
2 ber lin 
3 ber-lin 
4 Berlin 
5 Hamburg 
6 New York 
7 NewYork 

所以我的第一個假設是刪除任何特殊字符,包括空格,然後小寫。並查看誰匹配,然後將該ID寫入新表中?

什麼是最好和最可靠的方式來找到機器?

+0

你想在這裏做什麼?你想做全文搜索嗎? – 2014-10-31 23:52:16

+1

http://www.postgresonline.com/journal/archives/158-Where-is-soundex-and-other-warm-and-fuzzy-string-things.html – Donal 2014-10-31 23:53:41

+0

@SleimanJneidi那麼,不知道它是否是全文。在上面的例子中,我只想在一個新的表中看到如下結果:BERLIN 1,2,3,4 HAMBURG 5 NEWYORK 6,7 – dc10 2014-10-31 23:55:49

回答

1

如果除去一些字符(」「和‘ - 在實施例’)和下套管就足以識別重複:

CREATE TABLE tbl_folded AS 
SELECT lower(translate(name, ' -', '')) AS base_name 
    , array_agg(id) AS ids 
FROM tbl 
GROUP BY 1; 

SQL Fiddle.

translate()對於替換(或刪除)單個字符列表特別有用。
使用CREATE TABLE AS從查詢結果創建新表。

Postgres的圖案dba.SE匹配此相關答案功能的概述:

0

這當然可以優化,但它的工作原理:

CREATE TABLE test (id INT(9) NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL); 
INSERT INTO test (id, name) VALUES ('', 'berlin'); 
INSERT INTO test (id, name) VALUES ('', 'ber lin'); 
INSERT INTO test (id, name) VALUES ('', 'ber-lin'); 
INSERT INTO test (id, name) VALUES ('', 'Berlin'); 
INSERT INTO test (id, name) VALUES ('', 'Hamburg'); 
INSERT INTO test (id, name) VALUES ('', 'New York'); 
INSERT INTO test (id, name) VALUES ('', 'NewYork'); 

CREATE TABLE tmp_clean_text (id INT(9) NOT NULL, name VARCHAR(50) NOT NULL); 
INSERT INTO tmp_clean_text (id, name) SELECT id, REPLACE(REPLACE(LOWER(name), ' ', ''), '-', '') FROM test; 

CREATE TABLE results (name VARCHAR(50) NOT NULL); 

INSERT INTO results (name) SELECT DISTINCT name FROM tmp_clean_text; 
UPDATE results SET results.name = CONCAT(results.name, ' ', (
    SELECT GROUP_CONCAT(tmp_clean_text.id) 
    FROM tmp_clean_text 
    WHERE tmp_clean_text.name = results.name 
)); 

DROP TABLE tmp_clean_text; 
+0

像INT(9)或GROUP_CONCAT()這樣的元素是特定於MySQL的,並且在Postgres中不起作用。 – 2014-11-01 02:29:03

+0

對不起,我錯過了問題中的postgresql標籤。 – TwystO 2014-11-04 20:20:24

0

它看起來對我來說,你想低edit distance。當我使用低質量手動輸入的數據時遇到類似問題時,我使用了「正確」地名(可能是示例數據中的「紐約」)列表,然後使用所有行數據的交叉連接和所有正確的名稱,計算每個配對的編輯距離,並將每個配對的最小值作爲「匹配」。

PostgreSQL在其fuzzystrmatch庫中包含Levenshtein編輯距離函數,如其他人所述。

編輯:這裏的一些代碼,假設cities包含在後的數據和normalized_cities包含(HAMBURG, BERLIN, NEWYORK)每後來的評論:

select distinct id, name, first_value(normalized_name) 
     over (partition by id order by edit_distance) 
from (
select id, name, normalized_name, 
     levenshtein(upper(name), normalized_name) edit_distance 
    from cities cross join normalized_cities 
) all_pairs 

    id | name | first_value 
----+----------+------------- 
    1 | berlin | BERLIN 
    2 | ber lin | BERLIN 
    3 | ber-lin | BERLIN 
    4 | Berlin | BERLIN 
    5 | Hamburg | HAMBURG 
    6 | New York | NEWYORK 
    7 | NewYork | NEWYORK 
+0

不幸的是,我沒有一個標準化城市的名單。當然,你可以在網上找到一個,但我需要相同的邏輯,以匹配姓氏,這種方法是行不通的 – dc10 2014-11-01 10:22:58

+0

嗯,你可以交叉加入表本身@ dc10,但是你必須設置一些最大編輯距離,其中兩個條目可能被認爲是「相同的」,並且您可能需要有人蔘與審查這些選擇。 – 2014-11-01 10:44:23

+0

因爲我們談論超過1m記錄 – dc10 2014-11-01 10:52:31