【问题标题】:PostgreSQL - show data of previous year + current year's weekPostgreSQL - 显示上一年的数据+当年的一周
【发布时间】:2013-06-06 04:18:26
【问题描述】:

我需要创建一个列来显示前一年的利润,直到给定年份的一周。 因此,它将以周为单位划分当前年份,并显示给定周的利润是多少。 为了更清楚,假设上一年的利润是 1000。今年第一周的利润是 100,第二周的利润是 200,三分之二,周 -100(亏损)等等。 所以它应该是这样的:

week1|week2|week3|
1100 |1300 |1200 |

我尝试的是:

SELECT
CASE when f1.year = DATE_PART('year', now()) THEN f1.week END as week,
profit as profit
FROM (
SELECT 
DATE_PART('week', so.date_order) as week,
DATE_PART('year', so.date_order) as year,
so.profit as profit
FROM
sale_order as so
GROUP BY
week, year, profit
WHERE
so.date_order >= date_trunc('year', now() - '1 year'::interval)::timestamp::date  and so.date_order <= date_trunc('year', now()+ '1 year'::interval)::timestamp::date-1 
)as f1
GROUP BY
week, profit
ORDER BY
week

但这并没有按我的需要工作,因为它会在每个给定的星期分配利润。我的意思是它只显示那周的利润,但我需要“那周的利润”+“前几年的利润”。

我的查询尝试窗口函数:

(
SELECT
x.id as id,week as week, x.last_year_profit + y.running_profit as week_profit
FROM
(
SELECT
min(sol.id) as id,
 --DATE_PART('year',  so.date_order) AS calcyear, DATE_PART('week',  so.date_order) AS calcweek,
sum(sol.price_subtotal - (CASE WHEN sol.account_cost_amount != 0 THEN sol.account_cost_amount ELSE sol.purchase_price END )) as last_year_profit
-- sum(sol.price_subtotal) as price_unit, sum(sol.purchase_price) as purchase_price, sum(sol.account_cost_amount) as account_cost_amount
FROM
sale_order as so
INNER JOIN sale_order_line as sol ON (sol.order_id = so.id)
INNER JOIN res_partner as rp ON (so.partner_id = rp.id)
WHERE EXISTS (
SELECT * FROM  res_partner_category_rel rpcl
WHERE 
rpcl.partner_id=rp.id and rpcl.category_id=37
and (so.date_order >= date_trunc('year', now() - '1 year'::interval)::timestamp::date  and so.date_order <= date_trunc('year', now())::timestamp::date-1 )
and so.state != 'cancel'
)
) as x
CROSS JOIN (
SELECT
date_trunc('week', so.date_order) as week,
sum(sum(sol.price_subtotal - (CASE WHEN sol.account_cost_amount != 0 THEN sol.account_cost_amount ELSE sol.purchase_price END ))) OVER  ( ORDER BY date_trunc('week', so.date_order)) as running_profit

FROM
sale_order as so
INNER JOIN sale_order_line as sol ON (sol.order_id = so.id)
INNER JOIN res_partner as rp ON (so.partner_id = rp.id)
WHERE EXISTS (
SELECT * FROM  res_partner_category_rel rpcl
WHERE 
rpcl.partner_id=rp.id and rpcl.category_id=37
AND so.date_order >= date_trunc('year', now())::timestamp::date
AND    so.date_order <  date_trunc('year', now() + '1 year'::interval)::timestamp::date 
and so.state != 'cancel'
)
GROUP BY
week
) as y
GROUP BY
id, week,week_profit
) as f1

由于某种原因,它不会在几周内拆分利润,而是只显示一行总计,如下所示:

week    |week_profit|
20130114| 1500       |

【问题讨论】:

  • 请记住始终包含此类问题的表定义。你在psql\d tbl 中得到什么,简化为手头的Q。或者从pgAdmin 的SQL 窗格中复制它。
  • 在编辑您的问题时,您似乎忘记了我对表定义的要求。您正在引入新表但仍然没有表定义?所以你认为一个精心设计的答案是理所当然的,但你自己却不会回应一个简单的请求?请为现成的测试用例添加示例数据。最好是 SQLfiddle。
  • 对不起。那么问题是我将如何重新创建我正在运行的真实数据库的精确副本?我的意思是它有很多表,有很多关系等等。也许有一些方法可以从数据库中复制表以在 sqlfiddle 中重新创建它?还是我应该手动编写我需要的每个表来做一个例子?

标签: sql postgresql postgresql-9.2


【解决方案1】:

运行总和的基本查询

使用众所周知的聚合函数sum() 作为window function

SELECT week, x.last_year_profit + y.running_profit AS week_profit
FROM (         -- total last year
   SELECT sum(profit) AS last_year_profit
   FROM   sale_order
   WHERE  date_order >= date_trunc('year', now() - interval '1 year')
   AND    date_order <  date_trunc('year', now()) 
   ) x
CROSS JOIN (   -- running sum current year
   SELECT date_trunc('week', date_order) AS week
         ,sum(sum(profit)) OVER (ORDER BY date_trunc('week', date_order))
                                                        AS running_profit
   FROM   sale_order
   WHERE  date_order >= date_trunc('year', now() - interval '1 year')
   AND    date_order <  date_trunc('year', now() + interval '1 year')
   GROUP  BY 1
   ) y;

结果:

week       | week_profit
-----------+------------
2012-01-02 | 1100
2012-01-09 | 1300
2012-01-16 | 1200
...

这里的高级功能是我将 window聚合函数 组合在单个查询级别中 - 即使在单个表达式中(!),导致 SELECT项目,这可能会让无辜的眼睛感到惊讶:

sum(sum(profit)) OVER (ORDER BY date_trunc('week', date_order))

在这个密切相关的答案中找到有关其工作原理的详细说明:
Postgres window function and group by exception

还请注意我在您的查询中改进的多个其他细节。

->SQLfiddle

数组/交叉表()

在一行中累积所有周的原始方法是将结果聚合到一个数组中:

SELECT ARRAY( 
    SELECT x.last_year_profit + y.running_profit  -- only one column
    FROM (
    -- rest like query above
   ) a

结果:

{1100,1300,1200, ...}

或者,更高级的是,您使用crosstab() 查询,如以下相关答案中所述:
PostgreSQL Crosstab Query

许多相关的 crossbab 答案之一,特别是处理时间数据:
Querying row counts segregated by date ranges

【讨论】:

  • 感谢您的回答。我尝试了这种方法,但由于某种原因,我得到的结果总共只有一行。它将星期显示为日期时间 - 20130114T00:00:00,利润显示为总利润。看起来它没有在几周内分裂。我用我的新查询编辑了我的问题。
猜你喜欢
  • 2023-01-24
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多