按期间加入分组,完全加入不按预期工作

时间:2018-04-26 19:43:21

标签: sql postgresql

我有一张销售表:

SALES
|---------|-------------|-------------|
|  order  |   ammount   |  date       |
|---------|-------------|-------------|
|  001    | $2,000      | 2018-01-01  |
|  002    | $3,000      | 2018-01-01  |
|  003    | $1,500      | 2018-01-03  |
|  004    | $1,700      | 2018-01-04  |
|  005    | $1,800      | 2018-01-09  |
|  006    | $4,200      | 2018-01-11  |
|---------|-------------|-------------|

另外,我有一张表根据任意时间段对销售进行分组:

BUDGET PERIODS
|---------|-------------|--------------|
| ID      | start_date  | end_date     |
|---------|-------------|--------------|
| 1       | 2018-01-01  | 2018-01-02   | <- notice this is a 2 day period...
| 2       | 2018-01-03  | 2018-01-05   | <-- but this is 3 days
|---------|-------------|--------------|

所以,我的结果表查询如下所示:

GROUPED SALES
|--------------|---------------|-----------------|
| start_date   | end_date      | ammount         |
|--------------|---------------|-----------------|
| 2018-01-01   | 2018-01-02    | $5,000          |
| 2018-01-03   | 2018-01-05    | $3,200          |
|--------------|---------------|-----------------|

我是通过查询完成的:

SELECT
    bp.start_date,
    bp.end_date,
    SUM(s.ammount)
FROM
    budget_periods bp
LEFT JOIN 
    sales s ON s.date >= bp.start_date AND s.date <= bp.end_date
GROUP BY 
    start_date, 
    end_date
那时候一切都很棒。但是,我注意到,当然,一些销售不包括在内,因为它们不在预算期间。因此,我想把它们“包含在某个地方”。我决定“某处”将是销售周(使用Postgres中的周截断功能)。因此,我的分组销售现在应该是这样的:

GROUPED SALES
|--------------|---------------|-----------------|
| start_date   | end_date      | ammount         |
|--------------|---------------|-----------------|
| 2018-01-01   | 2018-01-02    | $5,000          |
| 2018-01-03   | 2018-01-05    | $3,200          |
| 2018-01-08   | 2018-01-14    | $6,000          |
|--------------|---------------|-----------------|

请注意,如果您截断2018-01-09和2018-01-11两周,则显示2018-01-08。要计算我的end_date,预算期限“默认”为七天,因此比start_date晚六天。

所以,我将查询修改为FULL JOIN,如下所示:

SELECT
    COALESCE(bp.start_date, DATE_TRUNC('WEEK', s.date)) AS new_start_date,
    COALESCE(bp.end_date, DATE_TRUNC('WEEK', s.date) + INTERVAL '6 DAY') AS new_end_date,
    SUM(s.ammount)
FROM
    budget_periods bp
FULL JOIN 
    sales s ON s.date >= bp.start_date AND s.date <= bp.end_date
GROUP BY 
    new_start_date, 
    new_end_date

但是,结果表与我有LEFT JOIN时的结果表相同。我该怎么做呢?

感谢您抽出时间阅读这么长时间解释问题。

1 个答案:

答案 0 :(得分:0)

如果您想要 sales 中的所有行,请将其作为Child中的第一个表。但是,我认为LEFT JOIN应该有效,FULL JOIN

LEFT JOIN

SELECT COALESCE(bp.start_date, DATE_TRUNC('WEEK', s.date)) as new_start_date, COALESCE(bp.end_date, DATE_TRUNC('WEEK', s.date) + interval '6 day') as new_end_date, SUM(s.amount) FROM sales s LEFT JOIN budget_periods bp ON s.date >= bp.start_date AND s.date <= bp.end_date GROUP BY new_start_date, new_end_date; 过滤掉事物的唯一原因是通过FULL JOIN子句,但你没有。{/ p>