如何使用Python Cubes返回2个维度的聚合值?

时间:2016-07-15 07:01:00

标签: postgresql data-warehouse olap olap-cube cubes

情况

使用Python 3,Django 1.9,Cubes 1.1和Postgres 9.5 这些是我的图片形式的数据表:

enter image description here

文本格式相同:

存储表

------------------------------
| id  | code | address       |
|-----|------|---------------|
| 1   | S1   | Kings Row     |
| 2   | S2   | Queens Street |
| 3   | S3   | Jacks Place   |
| 4   | S4   | Diamonds Alley|
| 5   | S5   | Hearts Road   |
------------------------------

产品表

------------------------------
| id  | code | name          |
|-----|------|---------------|
| 1   | P1   | Saucer 12     |
| 2   | P2   | Plate 15      |
| 3   | P3   | Saucer 13     |
| 4   | P4   | Saucer 14     |
| 5   | P5   | Plate 16      |
|  and many more ....        |
|1000 |P1000 | Bowl 25       |
|----------------------------|

销售表

----------------------------------------
| id  | product_id | store_id | amount |
|-----|------------|----------|--------|
| 1   | 1          | 1        |7.05    |
| 2   | 1          | 2        |9.00    |
| 3   | 2          | 3        |1.00    |
| 4   | 2          | 3        |1.00    |
| 5   | 2          | 5        |1.00    |
|  and many more ....                  |
| 1000| 20         | 4        |1.00    |
|--------------------------------------|

关系是:

  1. 销售属于商店
  2. 销售属于产品
  3. 商店有很多销售
  4. 产品有很多销售
  5. 我想要实现的目标

    我想使用立方体能够通过以下方式进行分页显示:

    鉴于商店S1-S3:

    -------------------------
    | product | S1 | S2 | S3 |
    |---------|----|----|----|
    |Saucer 12|7.05|9   | 0  |
    |Plate 15 |0   |0   | 2  |
    |  and many more ....    |
    |------------------------|
    

    请注意以下事项:

    1. 即使在商店S3下没有Saucer 12的销售记录,我显示0而不是null或没有。
    2. 我希望能够按商店排序,比如S3的降序。
    3. 单元格表示在该特定商店中花费的特定产品的总和。
    4. 我也希望有分页。
    5. 我尝试了什么

      这是我使用的配置:

      "cubes": [
          {
              "name": "sales",
              "dimensions": ["product", "store"],
              "joins": [
                  {"master":"product_id", "detail":"product.id"},
                  {"master":"store_id", "detail":"store.id"}
              ]
          }
      ],
      "dimensions": [
          { "name": "product", "attributes": ["code", "name"] },
          { "name": "store", "attributes": ["code", "address"] }
      ]
      

      这是我使用的代码:

       result = browser.aggregate(drilldown=['Store','Product'],
                                     order=[("Product.name","asc"), ("Store.name","desc"), ("total_products_sale", "desc")])
      

      我没有得到我想要的东西 我这样得到了:

      ----------------------------------------------
      | product_id | store_id | total_products_sale |
      |------------|----------|---------------------|
      | 1          | 1        |       7.05          |
      | 1          | 2        |       9             |
      | 2          | 3        |       2.00          |
      |  and many more ....                         |
      |---------------------------------------------|
      

      这是没有分页的整个表格,如果没有在该商店出售的产品,它将不会显示为零。

      我的问题

      我如何得到我想要的东西?

      在使用多维数据集运行查询之前,是否需要创建另一个按商店和产品聚合所有内容的数据表?

      更新

      我已阅读更多内容。我意识到我想要的是切割,因为我需要跨越两个维度。请参阅:https://en.wikipedia.org/wiki/OLAP_cube#Operations

      Cubes GitHub issues交叉发布以获得更多关注。

1 个答案:

答案 0 :(得分:1)

这是一个纯SQL解决方案,使用 crosstab() 从其他tablefunc模块到 pivot 聚合数据。它通常比任何客户端替代方案都表现更好。如果您不熟悉crosstab()请先阅读

关于"额外" crosstab()输出中的列:

SELECT product_id, product
     , COALESCE(s1, 0) AS s1               --  1. ... displayed 0 instead of null
     , COALESCE(s2, 0) AS s2
     , COALESCE(s3, 0) AS s3
     , COALESCE(s4, 0) AS s4
     , COALESCE(s5, 0) AS s5
FROM   crosstab(
     'SELECT s.product_id, p.name, s.store_id, s.sum_amount
      FROM   product p
      JOIN  (
         SELECT product_id, store_id
              , sum(amount) AS sum_amount  -- 3. SUM total of product spent in store
         FROM   sales
         GROUP  BY product_id, store_id
         ) s ON p.id = s.product_id
      ORDER  BY s.product_id, s.store_id;'
   , 'VALUES (1),(2),(3),(4),(5)'          -- desired store_id's
   ) AS ct (product_id int, product text   -- "extra" column
          , s1 numeric, s2 numeric, s3 numeric, s4 numeric, s5 numeric)
ORDER  BY s3 DESC;                         -- 2. ... descending order for S3

生成您想要的结果完全(加product_id)。

要包含从未销售过的产品,请将[INNER] JOIN替换为LEFT [OUTER] JOIN

带有基本查询的

SQL Fiddle tablefunc模块未安装在sqlfiddle上。

重点

  
      
  1. 我也希望有分页。
  2.   

最后一项是模糊的。可以使用LIMITOFFSET

进行简单的分页

我会考虑MATERIALIZED VIEW在分页前实现结果。如果你有一个稳定的页面大小,我会在MV中添加页码,以便轻松快速地获得结果。

要优化 big 结果集的效果,请考虑: