postgresql:通过左连接添加两个表并使用大小写时

时间:2018-04-02 11:25:10

标签: sql postgresql

有tableA和tableB,看起来像:

 tableA
+--------+------------+
| cst_id |   date01   |
+--------+------------+
|      1 | 2010/9/3   |
|      2 | 2010/12/26 |
|      3 | 2010/10/5  |
|      4 | 2010/11/27 |
|      2 | 2010/11/24 |
|      2 | 2010/7/14  |
|      3 | 2010/7/25  |
|      1 | 2010/11/15 |
|      1 | 2010/11/17 |
|      4 | 2010/8/11  |
|      5 | 2010/9/17  |
|      5 | 2010/9/27  |
|      6 | 2010/11/18 |
+--------+------------+

tableB
+--------+------------+-------+-----------+
| cst_id |   date02   | money | fund_type |
+--------+------------+-------+-----------+
|      1 | 2010/7/19  |    12 | A         |
|      1 | 2010/10/27 |    44 | A         |
|      2 | 2010/10/23 |     3 | A         |
|      3 | 2010/11/27 |     6 | B         |
|      3 | 2010/12/21 |    78 | C         |
|      2 | 2010/11/18 |    45 | C         |
|      4 | 2010/11/14 |   108 | B         |
|      1 | 2010/10/24 |    11 | A         |
|      2 | 2010/12/15 |    62 | D         |
|      3 | 2010/12/4  |    43 | C         |
|      4 | 2010/9/21  |   213 | C         |
+--------+------------+-------+-----------+

tableA是一个普通的客户表,而tableB是一个基金交易事实表。如何创建列:60tol_money(在date01之前的60天内,基金上花了多少钱),60tol_type(在date01之前的60天内,有多少)类型已被购买); 60天(在date01之前60天,已经进行了多少次交易),并得到:

tableC

+--------+------------+-------------+------------+---------+---------+---------+
| cst_id |   date01   | 60tol_money | 60tol_type | 14_days | 30_days | 60_days |
+--------+------------+-------------+------------+---------+---------+---------+
|      1 | 2010/9/3   | 12          | 1          |       1 |       1 |       1 |
|      2 | 2010/12/26 | 45+62       | 2(C+D)     |       1 |       1 |       2 |
|      3 | 2010/10/5  |             |            |         |         |         |
|      4 | 2010/11/27 |             |            |         |         |         |
|      2 | 2010/11/24 |             |            |         |         |         |
|      2 | 2010/7/14  |             |            |         |         |         |
|      3 | 2010/7/25  |             |            |         |         |         |
|      1 | 2010/11/15 |             |            |         |         |         |
|      1 | 2010/11/17 |             |            |         |         |         |
|      4 | 2010/8/11  |             |            |         |         |         |
|      5 | 2010/9/17  | 0           | 0          |       0 |       0 |       0 |
|      5 | 2010/9/27  | 0           | 0          |       0 |       0 |       0 |
|      6 | 2010/11/18 | 0           | 0          |       0 |       0 |       0 |
+--------+------------+-------------+------------+---------+---------+---------+

2 个答案:

答案 0 :(得分:1)

这是一个部分查询,请看它是如何运作的。其余的你可以根据这个来弄清楚自己。

SELECT
    a.cst_id,
    a.date01,
    SUM(CASE WHEN b.date02 BETWEEN a.date01 - 60 AND a.date01 THEN b.money ELSE 0 END) AS "60tol_money",
    COUNT(DISTINCT CASE WHEN b.date02 BETWEEN a.date01 - 60 AND a.date01 THEN b.fund_type END) AS "60tol_type"
FROM tableA a 
LEFT JOIN tableB b USING (cst_id)
GROUP BY a.cst_id, a.date01
ORDER BY a.cst_id, a.date01

简单地说,要获得60tol_money,如果date02在date01的60天内,则将该记录的货币值添加到总和中。如果不是,则将总和添加为零。对于基金类型,再次检查日期,如果有效则使用fund_type值,否则为NULL(暗示,因为我没有在其中放置ELSE)。然后只计算不同的基金类型(NULL不计数),以获得60tol_type值。

答案 1 :(得分:0)

如果您使用的是PostgreSQL 9.4及更高版本,则可以使用@eurotrash子句优化FILTER WHERE的查询,如下所示:

SELECT
    a.cst_id,
    a.date01,
    SUM(b.money) FILTER (WHERE b.date02 BETWEEN a.date01 - 60 AND a.date01) AS "60tol_money",
    COUNT(DISTINCT b.fund_type) FILTER (WHERE b.date02 BETWEEN a.date01 - 60 AND a.date01) AS "60tol_type"
FROM tableA a 
LEFT JOIN tableB b USING (cst_id)
GROUP BY a.cst_id, a.date01
ORDER BY a.cst_id, a.date01