Sql Oracle中如何利用模糊匹配实现精确连接
我正在尝试将一个表中的一组县名称与另一个表中的县名称连接起来。这里的问题是,两个表中的县名称都没有标准化。它们在数量上不一样;此外,它们可能不会总是以类似的模式出现。例如,表A中的县“圣约翰”可以表示为表B中的“圣约翰”。我们无法预测它们的共同模式 这意味着,我们不能在连接时使用等于=条件。所以,我尝试使用oracle中的JARO_WINKLER_相似性函数来加入它们。 我的左外连接条件如下:Sql Oracle中如何利用模糊匹配实现精确连接,sql,oracle,fuzzy-comparison,jaro-winkler,Sql,Oracle,Fuzzy Comparison,Jaro Winkler,我正在尝试将一个表中的一组县名称与另一个表中的县名称连接起来。这里的问题是,两个表中的县名称都没有标准化。它们在数量上不一样;此外,它们可能不会总是以类似的模式出现。例如,表A中的县“圣约翰”可以表示为表B中的“圣约翰”。我们无法预测它们的共同模式 这意味着,我们不能在连接时使用等于=条件。所以,我尝试使用oracle中的JARO_WINKLER_相似性函数来加入它们。 我的左外连接条件如下: Table_A.State = Table_B.State AND UTL_MATCH.JARO_W
Table_A.State = Table_B.State
AND UTL_MATCH.JARO_WINKLER_SIMILARITY(Table_A.County_Name,Table_B.County_Name)>=80
在对结果进行了一些测试之后,我给出了80分,这似乎是最优的。
这里的问题是,我加入时会出现一系列的误报。例如,如果在同一个州(例如巴里州和贝州)下有一些名称相似的县,那么如果度量值>=80,它们将被匹配。
这会创建不准确的关联数据集。
有人能提出一些建议吗
谢谢,
达夫
您能帮我建立一个查询,为表B/C/D中的每个记录查找表a,并与a中的县名称进行匹配,该县名称的相似度最高,即>=80吗
Oracle安装程序:
查询:
输出:
使用一些编好的测试数据内联,您可以使用自己的表A和表B代替前两个with子句,并从匹配项开始,如下所示: 结果:
STATE COUNTY_NAME MATCHED_NAME SCORE
----- ----------- ------------ ----------
A BARRY BARRY 100
A ST JOHNS SAINT JOHNS 80
B CHEESECAKE CHEESE 92
B WAFFLES WAFFLING 86
C UMBRELLAS UMBRELLAS 100
其思想是matches计算所有分数,ranked_matches在state、county_name中为其分配一个序列,最终查询将挑选所有得分最高的人,即排名过滤器=1
您可能仍然会得到一些重复项,因为无法阻止两个不同的模糊匹配获得相同的分数。也许您创建了一个包含已知误报的表,并使用a和表a.State、表a.County、表B.County不在选择状态,a、B来自已知误报检查?另一种可能是用您自己的实现来取代JARO_WINKLER_相似度,该实现具有所有必要的魔力…感谢您的评论。问题是我们需要检查每一条记录以了解误报。刚才我发现蒙哥马利与梦露在同一州的比赛分数为84。达到目标的另一种方法是先使用标准化函数,例如,用“ST”替换“SAINT”,然后使用JARO_WINKLER_相似度更高的阈值。如果过滤只保留排名最高的80以上的比赛,会发生什么对于表A中的每一行?那么结果有用吗?您是否也尝试过添加每个县的SOUNDEX值的比较。例如,梦露/蒙哥马利在84岁时比赛,但SOUNDEX不同。本质上,你的问题是你想要一个精确的匹配,使用“模糊”算法,这不可能总是有那个准确性。该死,MTO比我快。我试图避免使用额外的嵌套级别重复JWS函数,但我不知道这是否会在实践中对性能产生任何影响。
SELECT *
FROM (
SELECT wtm.word,
ow.word AS official_word,
UTL_MATCH.JARO_WINKLER_SIMILARITY( wtm.word, ow.word ) AS similarity,
ROW_NUMBER() OVER ( PARTITION BY wtm.word ORDER BY UTL_MATCH.JARO_WINKLER_SIMILARITY( wtm.word, ow.word ) DESC ) AS rn
FROM words_to_match wtm
INNER JOIN
official_words ow
ON ( UTL_MATCH.JARO_WINKLER_SIMILARITY( wtm.word, ow.word )>=80 )
)
WHERE rn = 1;
WORD OFFICIAL_WO SIMILARITY RN
-------------- ----------- ---------- ----------
MONROE ST MONROE 93 1
MONTGOMERY BAY MONTGOMERY 94 1
SAINT JOHN SAINT JOHNS 98 1
ST JAMES SAINT JAMES 80 1
with table_a (state, county_name) as
( select 'A', 'ST JOHNS' from dual union all
select 'A', 'BARRY' from dual union all
select 'B', 'CHEESECAKE' from dual union all
select 'B', 'WAFFLES' from dual union all
select 'C', 'UMBRELLAS' from dual )
, table_b (state, county_name) as
( select 'A', 'SAINT JOHNS' from dual union all
select 'A', 'SAINT JOANS' from dual union all
select 'A', 'BARRY' from dual union all
select 'A', 'BARRIERS' from dual union all
select 'A', 'BANANA' from dual union all
select 'A', 'BANOFFEE' from dual union all
select 'B', 'CHEESE' from dual union all
select 'B', 'CHIPS' from dual union all
select 'B', 'CHICKENS' from dual union all
select 'B', 'WAFFLING' from dual union all
select 'B', 'KITTENS' from dual union all
select 'C', 'PUPPIES' from dual union all
select 'C', 'UMBRIA' from dual union all
select 'C', 'UMBRELLAS' from dual )
, matches as
( select a.state, a.county_name, b.county_name as matched_name
, utl_match.jaro_winkler_similarity(a.county_name,b.county_name) as score
from table_a a
join table_b b on b.state = a.state )
, ranked_matches as
( select m.*
, rank() over (partition by m.state, m.county_name order by m.score desc) as ranking
from matches m
where score > 50 )
select rm.state, rm.county_name, rm. matched_name, rm.score
from ranked_matches rm
where ranking = 1
order by 1,2;
STATE COUNTY_NAME MATCHED_NAME SCORE
----- ----------- ------------ ----------
A BARRY BARRY 100
A ST JOHNS SAINT JOHNS 80
B CHEESECAKE CHEESE 92
B WAFFLES WAFFLING 86
C UMBRELLAS UMBRELLAS 100