甲骨文/ PLSQL。仅选择两个表之间的最佳匹配

时间:2012-10-02 13:22:56

标签: oracle match

我有两张桌子:

Vehicles 
make    model         modification    
Audi     A 5         A 5 2010 Sportsback 2.8      
Audi     A 5         A 5 2012 Quattro L     
Audi     A 5         A 5 Cabriolet 

matchingModel 
make    model      modContain    modEnd    finalModel    
Audi     A 5       Sportback              A5 Sportback
Audi     A 5                       L        A5 L
Audi     A 5                                A5

我的任务是通过查找匹配来获得最适合的finalModel(可以在下面的选择中看到)。 首先我试图加入表格

(SELECT 
matchingModel.finalModel
  FROM vehicles
    LEFT OUTER JOIN matchingModel ON 
matchingModel.TEXT1 = vehicles.make

    AND vehicles.model = nvl(matchingModel.model,vehicles.model)
    AND vehicles.modification LIKE decode(matchingModel.modContain, NULL, vehicles.modification, '%'||matchingModel.modContain||'%')
    AND vehicles.modification LIKE decode(matchingModel.modEnd, NULL, vehicles.modification, '%'||' '||matchingModel.modEnd)
)
AS bestMatch

但这不起作用,因为当Sportsback被发现为sportsback时,后来被覆盖为简单的A5,因为它也匹配。

接下来我简单地通过“nvling”所有可能的选项来实现这一点:nvl(nvl(nvl(选择make make,model fits和modContains位于修改中间,选项单元格为空),(选择make,模型拟合和modEnd就像修改的结束而modEnd不是空的),(选择make和model适合的地方等等))AS Bestmatch 这有效,但速度很慢(两个表都有超过500k的记录)。

这只是非常大的选择的一部分,所以很难重写这种正常的方式。 无论如何,问题是,是否有任何最佳实践如何在oracle中获得最佳匹配,只有一次,快速?我遇到的问题是性能,或者值适合两次,或者“where”子句不起作用,因为我不知道modContain或modEnd是否为空。

提前谢谢你。 对不起英文。

2 个答案:

答案 0 :(得分:1)

现在还没有完成,但我找到了一个例子,你可以继续为自己解决问题:SQL Fiddle Demo

select * from (
(select 
  case when v.modification like '%'||m.modContain||'%' then 2
       when m.modcontain is null                       then 1
                                                       else 0 end m1,
       case when v.modification like '%'||m.modend     then 2
            when m.modend is null                      then 1
                                                       else 0 end m2
 , m.make mmake, m.model mmodel, modcontain, modend, finalmodel
 , v.make vmake, v.model vmodel, modification
from vehicles v, matchingmodel m
where
     v.make  = m.make
 and soundex(v.model) = soundex(m.model) ) ) x
order by m1+m2 desc

因此子查询将匹配加在一起,最高匹配应该是您的最佳匹配。我还使用了soundex,它也可以帮助你,因为SportbackSportsback不完全相同,这帮助我使A5A 5相同。另外,为了加快速度,你需要分配好的指标和观察解释计划,特别是如果你有500k的记录。这不是一件容易的事。

关于编写程序(这是一个好主意)未经测试的想法可能看起来像这样:

create or replace function vehicle_matching(i_vehicles vehicles%rowtype,
                                            i_matchingmodel matchingmodel%rowtype)
return number
is
   l_return number;
begin
   if   i_vehicles.modification like '%'||i_matchingmodel.modContain||'%' then 
      l_return := 3;
   elsif soundex(i_vehicles.modification) like '%'||soundex(i_matchingmodel.modContain)||'%' then
      l_return := 2;
...

   if i_vehicles.modification like '%'||i_matchingmodel.modend then
      l_return := l_return + 1; -- there is no i++ in PL/SQL
   elsif 
...

   return l_return;
end vehicle_matching;

此外,我在考虑使用INSTRSUBSTR比使用%效率更高,但我实际上并不认为情况确实如此。

答案 1 :(得分:0)

你可以考虑这样的事情:

编写查询以在任何部分匹配时返回1 然后写另一个查询以在另一个部分匹配上返回另一个 - 等等。

对所有可能计入“相似性”的列重复此操作

最后,你会发现总和(或数量)最高的行为1,这将是最接近的匹配。