连接具有多个聚合级别的表

时间:2018-10-15 17:22:50

标签: sql postgresql join aggregation

我遇到了一个大问题,因为我正在尝试这样做:

[Edit]:基于@ gordon-linoff的评论,我用一个具体的例子来重塑我的问题

我必须加入两个表Sales和Quota。 表销售额:

+---------+---------+---------+---------+---------+---------+
| Country |   Year  | Store   | Manager |  Vendor | Customer|
+---------+---------+---------+---------+---------+---------+
|    MX   |   2018  |Cid. Mex.| Orlando |  Luiz   |   001   |
|    MX   |   2018  |Cid. Mex.| Orlando |  Fabio  |   002   |
|    MX   |   2018  |Cid. Mex.| Orlando |  Luiz   |   003   |
|    MX   |   2018  |Cid. Mex.| Orlando |  Juan   |   004   |
|    MX   |   2018  |Cid. Mex.| Orlando |  Juan   |   005   |
|    MX   |   2018  |Cid. Mex.| Javier  |Hernandez|   007   |
...

配额:

+---------+---------+---------+---------+---------+---------+------------+
| Country |   Year  | Store   | Manager |  Vendor | Customer|  Target    |
+---------+---------+---------+---------+---------+---------+------------+
|    MX   |  2018   |Cid. Mex.| Orlando |  Luiz   |  001    |     1,01   |
|    MX   |  2018   |Cid. Mex.| Orlando |  Fabio  |         |     2,00   |
|    MX   |  2018   |Cid. Mex.| Orlando |  Luiz   |         |     3,05   |
|    MX   |  2018   |Cid. Mex.| Orlando |  Juan   |  004    |     2,71   |
|    MX   |  2018   |Cid. Mex.| Orlando |         |         |    14,25   |
|    MX   |  2018   |Cid. Mex.|         |         |         |     16,1   |
...

最后我想要这样的事情: (销售加入配额):

|                     SALES FIELDS                          ||   QUOTA    |
+---------+---------+---------+---------+---------+---------++------------+
| Country |   Year  | Store   | Manager |  Vendor | Customer||  Target    |
+---------+---------+---------+---------+---------+---------++------------+
|    MX   |   2018  |Cid. Mex | Orlando |  Luiz   |  001    ||     1,01   | *1
|    MX   |   2018  |Cid. Mex | Orlando |  Fabio  |  002    ||     2,00   | *2
|    MX   |   2018  |Cid. Mex | Orlando |  Luiz   |  003    ||     3,05   | *3
|    MX   |   2018  |Cid. Mex | Orlando |  Juan   |  004    ||     2,71   | *4
|    MX   |   2018  |Cid. Mex | Orlando |  Juan   |  004    ||    14,25   | *5
|    MX   |   2018  |Cid. Mex | Javier  |Hernandez|  004    ||     16,1   | *6
...

说明我要寻找的结果:

  1. 由于这两个表中的“关键”国家/地区+年份+商店+经理+供应商+客户匹配,我从表“ Quota”中获取了“目标”。
  2. 在此示例中,为卖方Fabio定义了销售配额,而不论其客户是谁,因此Fabio出现的每一行(在同一国家/地区,同一年,同一家商店和同一位经理,都应作为“键”)出现他的配额。
  3. 在此示例中,我们看到为Luiz定义了配额(与为Fabio定义的配额一样),但是这次Luiz为客户001分配了配额,如示例(1)所示,但客户001是一个大客户,并且有一个特定的配额,对于其他所有客户,路易丝都有一个更开放的配额。
  4. 与示例(1)相同
  5. 在此示例中,我们看到了所有供应商的配额的“默认”值。由于路易斯,法比奥,胡安·埃尔南德斯都有自己的配额,因此这些值不会更改。
  6. 在这里,我们对配额使用“默认”值的概念相同,但是这次的级别高于上一个示例。

我认为现在更清楚了,但是如果仍然有一些阻碍理解的事情,请告诉我。

请帮助我。

预先感谢您。

2 个答案:

答案 0 :(得分:2)

此示例可能无法完美运行,但我认为您可以通过使用多个左联接和coalesce来完成所需的操作。试试这个,让我知道它有多近:

select
  s.*,
  coalesce (q1.target, q2.target, q3.target, q4.target) as target
from
  sales s
  left join quota q1 on
    s.country = q1.country and
    s.year = q1.year and
    s.manager = q1.manager and
    s.vendor = q1.vendor and
    s.customer = q1.customer
  left join quota q2 on
    s.country = q2.country and
    s.year = q2.year and
    s.manager = q2.manager and
    s.vendor = q2.vendor and
    q2.customer is null
  left join quota q3 on
    s.country = q3.country and
    s.year = q3.year and
    s.manager = q3.manager and
    q3.vendor is null and
    q3.customer is null
  left join quota q4 on
    s.country = q4.country and
    s.year = q4.year and
    q4.manager is null and
    q4.vendor is null and
    q4.customer is null

本质上,您正在对同一张表进行多个联接,并尝试首先选择具有最大匹配项的联接,然后向下层叠直到找到匹配项。

答案 1 :(得分:0)

您的错误示例使任务看起来比实际要复杂:-)您想要的归结为:从我们发现的销售记录的配额匹配中,进行最精确的匹配。

在PostgreSQL中,您可以使用DISTINCT ON执行此操作。在其他DBMS中,您可以将ROW_NUMBERFETCH FIRST ROW WITH TIES等结合使用。

select distinct on (s.customer, s.country, s.vendor, s.manager, s.store, s.year)
  s.*, q.target
from sales s
join quota q on  (q.country = s.country or q.country is null)
             and (q.year = s.year or q.year is null)
             and (q.store = s.store or q.store is null)
             and (q.manager = s.manager or q.manager is null)
             and (q.vendor = s.vendor or q.vendor is null)
             and (q.customer = s.customer or q.customer is null)
order by
  s.customer, s.country, s.vendor, s.manager, s.store, s.year,
  num_nonnulls(q.country, q.year, q.store, q.manager, q.vendor, q.customer) desc;