2017-01-10 49 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 
相關問題