Mysql 如何查找具有最大匹配列的行?
如果有三个表,TableItem、TableAbcd和TablePQR,如下所示Mysql 如何查找具有最大匹配列的行?,mysql,sql,left-join,database-administration,Mysql,Sql,Left Join,Database Administration,如果有三个表,TableItem、TableAbcd和TablePQR,如下所示 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
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中的列数相匹配。
因为表格ABCD的第1行与表格PQRS的第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)
如果fetch给我两条记录,我知道可能存在设计问题,但我们正在从第三方遗留系统获取数据,该系统根据需要具有表结构,并将其发送到另一个接口
请建议。这里的问题是:B和C之间有多少列匹配 对于join子句,您只需要b中至少有一列与c中的同一列匹配:
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
您可以通过以下方式进行计算:
(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
然后只需通过匹配行(子代)进行排序,并将结果限制为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示例来检查它:使用
表格ABCD
调用a
和表格pqrs
调用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)
);
在下面的代码中,您可以看到另一个过滤选项。它与McNets提出的方法类似,但使用窗口函数 关键是计算一个排名,该排名允许确定具有最佳匹配的TablePqrs行。另一方面,如果两行对于相同的项目值具有相同的排名,则我们必须使用其他标准来撤消平局。在本例中,条件是表的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
我尝试了下面的方法,效果很好,合并帮助我根据我在其中提到的顺序优先选择哪个值
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
到目前为止您尝试了什么?您使用的数据库是什么?您的“条件连接”在哪里?MySQL还是MSSQL?#DomySchoolWorkPlease这看起来是一个糟糕的设计问题,但在抽象意义上,很难说感谢McNets,但Limit将只返回一个项目的记录,我可能有多个项目。对于每一个项目,我需要一个最匹配的记录。我已经想出了我的解决方案,我会张贴完成后。谢谢你的帮助。但根据性能,我的解决方案可能不是最好的。太好了。尽管如此,看起来还是很糟糕的设计。