Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何查找具有最大匹配列的行?_Mysql_Sql_Left Join_Database Administration - Fatal编程技术网

Mysql 如何查找具有最大匹配列的行?

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、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      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将只返回一个项目的记录,我可能有多个项目。对于每一个项目,我需要一个最匹配的记录。我已经想出了我的解决方案,我会张贴完成后。谢谢你的帮助。但根据性能,我的解决方案可能不是最好的。太好了。尽管如此,看起来还是很糟糕的设计。