2017-01-10 47 views
0

如果有三个表,表项,TableAbcd和TablePqrs,如下如何查找具有最大匹配列的行?

TableItem 
ID item 
1 item1 

TableAbcd 
ID Item ColA ColB ColC ColD 
1 item1 A1  B1  C1  D1 


TablePqrs 
ID item ColA ColB ColC ColD ColValue 
1 item1 A1  B1  null null 10000 
2 item1 A1  B1  C1  D1  100 

这里,对于一个给定的项目,必须有其在TableAbcd和TablePqrs匹配的最大列数输出只是一个记录。 由于TableAbcd的1行有TablePqrs行最大匹配列2

我的输出,用于上述三个表应加入,

item ColA ColB ColC ColD ColValue 
item1 A1  B1  C1  D1  100 

代码试图到目前为止,

Select item, ColA, ColB, ColC, ColD, ColValue 
    FROM TableItem a 
     LEFT OUTER JOIN TableAbcd b 
     ON a.item = b.item  
     LEFT OUTER JOIN TablePqrs c 
     ON (b.ColA = c.ColA AND b.ColB = c.ColB AND b.ColC = c.ColC AND b.ColD = c.ColD) 
     OR (b.ColA = c.ColA AND b.ColB = c.ColB AND b.ColC = c.ColC) 
     OR (b.ColA = c.ColA AND b.ColB = c.ColB) 

如果提取我两条记录,我知道可能存在设计问题,但我们从第三方遗留系统获取数据,该系统根据其需要具有表结构,并将其发送到另一个接口。

请建议。

+0

那你试试这么远吗? – Renzo

+0

你在用什么数据库? –

+0

你的“条件连接”在哪里? MySQL或MSSQL? –

回答

0

我试过下面的东西,它的工作,合并帮助我优先选择哪个值取决于我提到的顺序。

Select item, ColA, ColB, ColC, ColD, ColValue 
    FROM TableItem a 
    LEFT OUTER JOIN (
     SELECT item, 
      COALESCE(c1.ColValue,c2.ColValue,c3.ColValue) ColValue 
     FROM abc b 
     LEFT OUTER JOIN pqr c1 
      ON b.ColA = c1.ColA AND b.ColB = c1.ColB AND b.ColC = c1.ColC AND b.ColD = c1.ColD 
     LEFT OUTER JOIN pqr c2 
      ON b.ColA = c2.ColA AND b.ColB = c2.ColB AND b.ColC = c2.ColC 
     LEFT OUTER JOIN pqr c3 
      ON b.ColA = c3.ColA AND b.ColB = c3.ColB 
     GROUP BY item 
    ) as Fact 
    ON Fact.item = a.item 
+0

太好了。尽管如此,看起来仍然很糟糕。 – Strawberry

1

这里的问题是:B和C之间有多少列匹配?

对于连接语句,你只需要一个B的至少一列在相同c柱相匹配:

(case when c.A = b.A then 1 else 0 end) 
+ (case when c.B = b.B then 1 else 0 end) 
+ (case when c.C = b.B then 1 else 0 end) 
+ (case when c.D = b.D then 1 else 0 end) as matches 

然后简单地为了通过匹配:

from c 
left join b 
    on c.A = b.A or c.B = b.B or c.C = b.C or c.D = b.D 

您可以通过calc下它行(后代)并将结果限制为1行。

select 
    c.id, c.item, c.A, c.B, c.C, c.D, c.colValue, 
    (case when c.A = b.A then 1 else 0 end) 
    + (case when c.B = b.B then 1 else 0 end) 
    + (case when c.C = b.B then 1 else 0 end) 
    + (case when c.D = b.D then 1 else 0 end) as matches 
from c 
left join b 
    on c.A = b.A or c.B = b.B or c.C = b.C or c.D = b.D 
order by 
    ((case when c.A = b.A then 1 else 0 end) 
    + (case when c.B = b.B then 1 else 0 end) 
    + (case when c.C = b.B then 1 else 0 end) 
    + (case when c.D = b.D then 1 else 0 end)) desc 
limit 1; 

我已经成立了一个rextester例子只是为了检查它:http://rextester.com/IPA67860

+0

谢谢McNets,但是Limit只会返回一个项目的记录,我可能有多个项目。对于每个项目,我需要一个最匹配的记录。 – ViS

+0

我已经想出了我的解决方案,我会发布一次完成。感谢你的帮助。但我的解决方案可能不是最好的表现。 – ViS

0

随着TableAbcd称为aTablePqrs称为p,匹配的数目为(p.cola = a.cola) + (p.colb = a.colb) + (p.colc = a.colc) + (p.cold = a.cold),因为在MySQL true为1和false是0.

现在,你正在寻找p记录,其中有更多匹配的记录存在其他p记录:

select * 
from tablepqrs p1 
where not exists 
(
    select * 
    from tablepqrs p2 
    join tableabcd a on a.item = p2.item 
    where p2.item = p1.item 
    and (p2.cola = a.cola) + (p2.colb = a.colb) + (p2.colc = a.colc) + (p2.cold = a.cold) > 
     (p1.cola = a.cola) + (p1.colb = a.colb) + (p1.colc = a.colc) + (p1.cold = a.cold) 
); 
0

在下面的代码中,您可以看到另一个选项进行过滤。它与McNets提出的方法类似,但使用窗函数。

关键是计算一个排名,它允许确定TablePqrs行与最佳匹配。另一方面,如果两行对同一项目值具有相同的排名,那么我们必须使用附加条件来撤消联系。在示例中,标准是TableAbcd表的ID。我没有使用外连接,所以没有匹配排名的TableItems记录没有结果。

我不太确定它是否真的适合你真正想要的,只需尝试一下并得出你自己的结论。

SELECT TableItem.id, 
     TableItem.item, 
     TablePqrs.colA, 
     TablePqrs.colB, 
     TablePqrs.colC, 
     TablePqrs.colD, 
     TablePqrs.value 
    FROM TableItem 
    INNER JOIN (SELECT DISTINCT 
        tableItemId, 
        FIRST_VALUE(tablePqrsId) OVER (PARTITION BY tableItemId ORDER BY ranking DESC, tablePqrsId DESC) tablePqrsId 
      FROM (SELECT rankTableItem.ID tableItemId, 
         rankTablePqrs.ID tablePqrsId, 
         CASE WHEN rankTablePqrs.colA IS NULL THEN 0 ELSE 1 END + 
         CASE WHEN rankTablePqrs.colB IS NULL THEN 0 ELSE 1 END + 
         CASE WHEN rankTablePqrs.colC IS NULL THEN 0 ELSE 1 END + 
         CASE WHEN rankTablePqrs.colD IS NULL THEN 0 ELSE 1 END ranking 
        FROM TableItem rankTableItem 
        INNER JOIN TableAbcd rankTableAbcd ON rankTableItem.item = rankTableAbcd.item  
        INNER JOIN TablePqrs rankTablePqrs ON rankTablePqrs.item = rankTableAbcd.item 
                 AND (rankTableAbcd.colA = rankTablePqrs.colA 
                   OR rankTableAbcd.colB = rankTablePqrs.colB 
                   OR rankTableAbcd.colC = rankTablePqrs.colC 
                   OR rankTableAbcd.colD = rankTablePqrs.colD))) pivotTable ON pivotTable.tableItemId = TableItem.Id 
    INNER JOIN TablePqrs ON TablePqrs.Id = pivotTable.tablePqrsId 
相关问题