SQL帮助-联接小的查找表,其中并非所有列都是必需的(和其他选项)

时间:2019-02-06 21:40:40

标签: sql join

我有一个包含事务的大表和一个较小的查找表,该表具有要基于4个公共列添加的值。这里的技巧不是查找表中会存在这4列的每种组合,并且在某些情况下,我希望它停止检查并接受匹配项,而不是转到下一列。如果没有任何其他选项,我还默认设置为“其他”选项。

表结构是这样的:

transaction_table
country, trans_id, store_type, store_name, channel, browser, purchase_amount, currency

lookup_table
country, store_name, channel, browser, trans_fee

数据可能是这样的:

transaction_table:

country| trans_id| store_type  |store_name  |channel |browser |amt  |currency
US     | 001     | Big Box     | Target     | B&M    |N/A     |1.45 |USD    
US     | 002     | Big Box     | Target     | Online |Chrome  |1.79 |USD   
US     | 003     | Small       | Bob's Store| B&M    |N/A     |2.50 |USD   
US     | 004     | Big Box     | Walmart    | B&M    |N/A     |1.12 |USD   
US     | 005     | Big Box     | Walmart    | Online |Firefox |3.79 |USD   
US     | 006     | Big Box     | Amazon     | Online |IE      |4.54 |USD   
US     | 007     | Small       | Jim's Plc  | B&M    |IE      |2.49 |USD 

lookup_table:
country|store_name  |channel |browser |trans_fee
US     |Target      |B&M     |N/A     |0.25   
US     |Target      |Online  |        |0.15
US     |Walmart     |        |        |0.30
US     |Other       |        |        |0.45

因此查看lookup_table数据:

  • 第1行非常具体,将与所有4个连接匹配 列。
  • 第2行不会在塔吉特购物时使用哪种浏览器 无论“浏览器”值如何,trans_fee都应返回 一样(其他商店可能会在意)。
  • 第3行表示与某个国家/地区“ US”进行的任何交易, store_name ='Walmart',与其余联接列无关 将具有相同的trans_fee
  • 第4行是“其他”情况,应首先查看 store_name列,如果找不到匹配项,请转到其他。

lookup_table数据可能会发生变化,并且最终可能取决于时间(添加了start_date和end_date列),因此对于长而复杂的CASE语句,它实际上不是一个好的选择。

我当时在想用IF IN语句检查每一列,但我希望有一个更直接的条件连接类型语句,可以用来逐列浏览并有其他选择。

谢谢!

edit:我没有指定它,但我想基本上从transaction_table返回所有数据,并将相应的trans_fee添加到每一行。

2 个答案:

答案 0 :(得分:0)

您将需要使用条件JOIN。

类似这样的东西

SELECT * 
FROM lookup_table
LEFT OUTER JOIN transaction_table
ON CASE WHEN lookup_table.store_name IS NOT NULL 
THEN transacton_table.store_name = lookup_table.store_name END

答案 1 :(得分:0)

这种部分匹配很棘手。而且您的问题并不是设置得很好。您似乎在某些列中有NULL,在其他列中有常规值。

在任何情况下,您都可以通过匹配可以解决的问题,然后使用order by获得最佳匹配。就您而言,我认为这是这样的:

select tt.*,
       (select trans_fee
        from lookup l
        where l.country = tt.country and
              l.store_name in ('other', tt.store_name) and
              (l.channel = tt.channel or l.channel is null) and
              (l.browser = tt.browser or l. browser is null)
        order by (case when l.store_name = tt.store_name then 1 else 2 end),
                 (case when l.channel = tt.channel then 1 else 2 end),
                 (case when l.browser = tt.browser then 1 else 2 end)
        fetch first 1 row only
       ) as trans_fee
from transaction_table tt;

这是通用SQL。但是,同样的想法应该适用于任何数据库。