Выберите аналогичное значение в столбце из другой таблицы и используйте другое значение таблицы в основной таблице. - PullRequest
0 голосов
/ 02 октября 2019

У меня есть таблица1 со всеми названиями магазинов, как показано ниже:

Таблица 1

id|name
1 |wairau road

Во второй таблице 2 у меня есть следующее значение:

Таблица 2

id|name        |customer_name
 1|wairau rd   |shelly
 2|wairau road |andy
 3|wairauroad  |ally

Когда я делаю select * from table 2,

Мой ожидаемый результат будет следующим:

id |name | customer_name 1 | wairau road | shelly 2 | wairau road | andy 3 | wairau road | ally

Заметил, что имя теперь синхронизируется с именем из таблицы1. Есть ли способ, которым мы можем сделать это в postgres / redshift SQL?

Ответы [ 2 ]

2 голосов
/ 02 октября 2019

Как вы уже слышали, решение для грязных данных заключается в их очистке. Если вы имеете дело с адресными данными, как вы показываете, стандартизация адресов является хорошим предметом для изучения самостоятельно. Это настолько распространенная проблема, что существует множество решений и услуг. Лучший подход может во многом зависеть от того, какие страны вам необходимо поддерживать, и каков ваш бюджет.

У вас уже есть хорошее предложение использовать soundex, чтобы помочь с этим. То, что делает soundex - это переводит строки в код, чтобы строки с похожим звучанием конвертировались в один и тот же код. Этот перевод может быть подготовлен заранее и сохранен в индексе, который может очень быстро выполнять сравнение с soundex. С другой стороны, soundex был из ста лет назад, предназначался для подсчета фамилий и был создан для версии американского английского. Так что это не лучший выбор для каждой проблемы. Вы найдете Meataphone в том же расширении, оно потенциально немного лучше, но более или менее имеет те же плюсы и минусы. Это расширение также имеет расстояние Левенштейна, также называемое «редактировать расстояние». Он подсчитывает, сколько изменений нужно сделать, чтобы превратить одну строку в другую. Это лучше на длинных струнах, чем на очень коротких. Это здорово! Но это также не то, что вы можете рассчитать заранее, так как вы не знаете, с чем собираетесь сравнивать. Но это хороший инструмент для ранжирования похожих строк, если вы нашли какие-то вероятные совпадения другими способами.

Говоря о других средствах, в Postgres есть еще один отличный инструмент для проверки:

https://www.postgresql.org/docs/current/pgtrgm.html

Это часть стандартного пакета, поэтому вы должны установить его так же, как инструкции, которые вы уже получили для fuzzystringmatch. Триграммы - это мир за пределами простых нечетких совпадений строк, перечисленных выше. За ними стоит тонна исследований, они хорошо работают на разных языках и наборах данных, отличные вещи. Наконец-то я потратил некоторое время на рассмотрение реализации Postgres на прошлой неделе, и это здорово

select 'wairau rd' as address, show_trgm('wairau rd')   union all
select 'wairau rd' as address, show_trgm('wairau road') union all
select 'wairau rd' as address, show_trgm('wairauroad')

Это выглядит примерно так:

address,show_trgm
wairau rd,"{""  r"",""  w"","" rd"","" wa"",air,""au "",ira,rau,""rd "",wai}"
wairau rd,"{""  r"",""  w"","" ro"","" wa"",""ad "",air,""au "",ira,oad,rau,roa,wai}"
wairau rd,"{""  w"","" wa"",""ad "",air,aur,ira,oad,rau,roa,uro,wai}"

Волшебная часть заключается в том, что Postgres может использовать этикуски, чтобы сделать некоторые действительно хорошие сравнения и догадки с индексом. Поскольку индекс находится на этих крошечных кусках, которые покрывают всю строку, вы избавляетесь от ограничений левого якоря стандартного B-дерева. Это обеспечивает большую гибкость и мощь без замедления запросов.

Существует два способа настройки индекса в зависимости от того, какие сравнения вам интересны. Есть некоторое время и пространство для торговли. тоже, но это то, что нужно проверить, если вы уверены, что этот инструмент вам даже подойдет. Вот два индекса:

CREATE INDEX table_1_names_gin
    ON table1
    USING gin (address gin_trgm_ops);

CREATE INDEX table_1_names_gist
    ON table1
    USING gist (address gist_trgm_ops);

Я называю ваше поле "адрес" здесь, так как я бы не назвал имя поля. Если у вас есть такие индексы, вы можете выполнять быстрый поиск LIKE или ILIKE и поиск соответствия шаблону без сложного синтаксиса регулярного выражения. Что-то вроде этого (не проверено) для поиска при запуске:

select * 
  from table2
 where address ILIKE 'wairu%'

или даже это для поиска по содержанию:

select * 
  from table2
 where address ILIKE 'wairu%'

Или это для поиска сходства: from analytic_scan

select * 
  from table2
 where address %> 'wairu'

Это намного больше, но я остановлюсь. И, честно говоря, стандартизация адресов должна быть вашим первым шагом, несмотря ни на что. Но нечеткое сопоставление может помочь.

Совет. В прошлом я обнаружил, что часто есть хорошие (юзабилити / UX) причины, по которым люди вводят неверные или противоречивые адреса. Если ваша база данных является частью корпоративного приложения, один из вариантов - запускать отчет каждую ночь, находя и помечая адреса или имена, которые выглядят нестандартно. Нечеткое сопоставление может быть действительно полезным здесь. Тогда кто-то может помочь обучить людей, которые делают ошибки, делать лучше. Или, может быть, вы обнаружите, что пользовательский интерфейс системы облегчает ввод плохих данных, а не хороших. В этом случае вы можете переработать приложение, чтобы оно стало лучше, и измерить изменения в почти дубликатах, чтобы оценить, насколько хорошо вы делаете.

1 голос
/ 02 октября 2019

Вы можете использовать soundex (в расширении fuzzystrmatch). Протестируйте в скрипту SQL

CREATE EXTENSION if not exists fuzzystrmatch;
CREATE TABLE t1 (id int, name text);
CREATE TABLE t2 (id int, name text, customer_name text);

INSERT INTO t1 VALUES (1, 'wairau road');
INSERT INTO t1 VALUES (2, 'joe road');
INSERT INTO t1 VALUES (3, 'jerry road');
INSERT INTO t2 VALUES (1, 'wairau rd', 'shelly');
INSERT INTO t2 VALUES (2, 'wairau road', 'andy');
INSERT INTO t2 VALUES (3, 'wairauroad', 'ally');
INSERT INTO t2 VALUES (4, 'joe  row', 'john');
INSERT INTO t2 VALUES (5, 'joe.rd', 'jack');

SELECT DISTINCT ON (t2.id) t2.id, t1.name, t2.customer_name,
                           t2.name AS data_entry_name
FROM t2
CROSS JOIN t1
ORDER BY t2.id, t1.name = t2.name DESC, difference(t1.name, t2.name) DESC, t1.name

Запрос может быть довольно медленным, если данных много. Он выбирает наиболее вероятное совпадение через ORDER BY, в данном случае, в следующем порядке:

  1. , если имена абсолютно совпадают
  2. , если имена похожи (1 = не похожи.. 4 = очень похоже)
  3. алфавитный порядок имен в таблице 1

Вы можете добавить дополнительные правила, например, если строчная версия без пробелов совпадает.

Проблема с этим запросом состоит в том, что он покажет наиболее вероятное совпадение, которое может быть совершенно неверным при отсутствии вероятного совпадения. Кроме того, это лучшее предположение, поэтому запрос может сделать неправильный выбор.

...