查询以找到最匹配的内容

时间:2019-05-13 01:11:06

标签: sql tsql

我有2张桌子,

Table1                               Table2
+----------+--------+----------+     +--------+---------+-------+
| Customer | Part # | Modifier |     | Part # | Modifer | Value |
+----------+--------+----------+     +--------+---------+-------+
| Fred     |      1 | XYZ      |     |      1 | Null    | 1.5   |
| Fred     |      2 | ABC      |     |      1 | GHI     | 2.0   |
| Fred     |      2 | DEF      |     |      2 | Null    | 3.0   |
| Fred     |      2 | GHI      |     |      2 | ABC     | 3.1   |
| Fred     |      3 | ABC      |     |      2 | DEF     | 3.2   |
| Fred     |      3 | XYZ      |     |      3 | Null    | 8.0   |
| Fred     |      4 | ABC      |     |      4 | Null    | 10.0  |
| Lucy     |      1 | GHI      |     |      5 | Null    | 4.0   |
| Lucy     |      5 | DEF      |     |      5 | ABC     | 4.5   |
| Lucy     |      4 | Null     |     |      5 | DEF     | 4.7   |
+----------+--------+----------+     +--------+---------+-------+

保证ABC,DEF和GHI是表2中唯一的修饰符,因此出于表2的目的可以忽略XYZ。我希望创建一个将Table1连接到Table2的查询,每个客户/部件号只有1个结果,因此连接的结果将是:

+----------+--------+-------+
| Customer | Part # | Value |
+----------+--------+-------+
| Fred     |      1 | 1.5   |
| Fred     |      2 | 3.0   |
| Fred     |      3 | 8.0   |
| Fred     |      4 | 10.0  |
| Lucy     |      1 | 2.0   |
| Lucy     |      5 | 4.7   |
| Lucy     |      4 | 10.0  |
+----------+--------+-------+

规则是每个客户每个零件编号只能使用1个修饰符(ABC,DEF,GHI)。因此,Fred,第2部分是错误情况,应返回Null修饰符或3.0的值。如果使用的修饰符不是3个中的1个,则将其视为没有修饰符(或Null)。基本上,除非有单个相关的修饰符(ABC,DEF,GHI)并且为零件#定义了该修饰符,否则应始终返回Null修饰符的值。

我不应该去哪个方向。在不同条件下多次加入Table2吗?使用OVER / PARTITION BY以某种方式对结果进行排名并选择排名靠前的结果?我尝试了几种不同的解决方案,但始终似乎忽略了其中一种条件。

预先感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

您可以使用以下方法设置默认值:

select t1.*, coalesce(t2.value, t2null.value) as value
from table1 t1 left join
     table2 t2
     on t1.part = t2.part and
        t1.modifier = t2.modifier left join
     table2 t2null
     on t1.part = t2null.part and
        t2null.modifier is null;

然后每个客户/零件获得一个:

select t.*
from (select t1.*, coalesce(t2.value, t2null.value) as value,
             row_number() over (partition by t1.customer, t1.part
                                order by (case when t2.value is not null then 1 else 2 end)
                               ) as seqnum
      from (select t1.*, 
                   sum(case when part in ('ABC', 'DEF', 'GHI') then 1 else 0 end) over (partition by customer) as cnt
            from table1 t1
           ) t1 left join
           table2 t2
           on t1.part = t2.part and
              t1.modifier = t2.modifier and
              t1.cnt = 1 left join
           table2 t2null
           on t1.part = t2null.part and
              t2null.modifier is null
      ) t
where seqnum = 1;