2017-01-10 7 views
0

Если есть три таблицы, TableItem, 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 , Поскольку строка 1 из TableAbcd имеет максимальные столбцы совпадающие с 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) 

если fetch мне две записи, я знаю, что могут возникнуть проблемы с дизайном, но мы получаем данные от сторонней системы устаревания, которая имеет структуру таблицы в соответствии с ее потребностями и отправляет ее другому интерфейсу.

Просьба предложить.

+0

Что вы пытались до сих пор? – Renzo

+0

Какая БД вы используете? –

+0

Где твое "условное соединение"? MySQL или MSSQL? –

ответ

0

Я попытался ниже вещь, и она работала, то COALESCE помогает мне приоритеты, какое значение выбрать в зависимости от того, я упомянул в нем.

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?

Для объединения пункт вам нужно только то, что по крайней мере один столбец б совпадает с той же колонке в с:

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 его:

(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 просто проверить его: http://rextester.com/IPA67860

+0

Спасибо McNets, но Limit вернет мне только запись для одного элемента, у меня может быть несколько элементов. для каждого элемента мне нужна самая подходящая запись. – ViS

+0

Я понял мое решение, я опубликую его после завершения. Ценю вашу помощь. Но мое решение может быть не лучшим по производительности. – ViS

0

С TableAbcd под названием a и TablePqrs под названием 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 с наилучшим соответствием. С другой стороны, если две строки имеют одинаковый рейтинг для одного и того же значения элемента, мы должны использовать дополнительные критерии, чтобы отменить связь. в этом примере критерием является ID таблицы TableAbcd. Я не использую внешние соединения, поэтому результаты для записей 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