Postgresql查询每天售出的库存数量

时间:2017-02-13 05:25:27

标签: sql postgresql pivot

我有CRM项目,负责维护每个组织的产品销售订单。

我想计算每天售出的股票,我已经设法按日期循环,但显然这是一种荒谬的方法,并且需要更多的时间和记忆。

请帮我在单个查询中找到它。有可能吗?

这是我的数据库结构供您参考。

产品:id(PK),名称

组织:id(PK),名称

sales_order :ID(PK),product_id(FK),organization_id(FK),sold_stock,sold_date(纪元时间)

enter image description here

所选月份的预期输出:

organization |  product | day1_sold_stock | day2_sold_stock | ..... | day30_sold_stock

http://sqlfiddle.com/#!15/e1dc3/3

3 个答案:

答案 0 :(得分:2)

创建tablfunc:

CREATE EXTENSION IF NOT EXISTS tablefunc;

查询:

select  "proId" as ProductId ,product_name as ProductName,organizationName as OrganizationName,
    coalesce( "1-day",0) as  "1-day" ,coalesce( "2-day",0) as  "2-day" ,coalesce( "3-day",0) as "3-day" ,
    coalesce( "4-day",0) as  "4-day" ,coalesce( "5-day",0) as  "5-day" ,coalesce( "6-day",0) as  "6-day" ,
    coalesce( "7-day",0) as  "7-day" ,coalesce( "8-day",0) as  "8-day" ,coalesce( "9-day",0) as "9-day" ,
    coalesce("10-day",0) as "10-day" ,coalesce("11-day",0) as "11-day" ,coalesce("12-day",0) as "12-day" ,
    coalesce("13-day",0) as "13-day" ,coalesce("14-day",0) as "14-day" ,coalesce("15-day",0) as"15-day" ,
    coalesce("16-day",0) as "16-day" ,coalesce("17-day",0) as "17-day" ,coalesce("18-day",0) as "18-day" ,
    coalesce("19-day",0) as "19-day" ,coalesce("20-day",0) as "20-day" ,coalesce("21-day",0) as"21-day" ,
    coalesce("22-day",0) as "22-day" ,coalesce("23-day",0) as "23-day" ,coalesce("24-day",0) as "24-day" ,
    coalesce("25-day",0) as "25-day" ,coalesce("26-day",0) as "26-day" ,coalesce("27-day",0) as"27-day" ,
    coalesce("28-day",0) as "28-day" ,coalesce("29-day",0) as "29-day" ,coalesce("30-day",0) as "30-day" ,
    coalesce("31-day",0) as"31-day" 
from crosstab(
    'select hist.product_id,pr.name,o.name,EXTRACT(day FROM TO_TIMESTAMP(hist.sold_date/1000)),sum(sold_stock)
    from sales_order hist 
    left join product pr on pr.id = hist.product_id
    left join organization o on o.id = hist.organization_id
    where EXTRACT(MONTH FROM TO_TIMESTAMP(hist.sold_date/1000)) =5
    and EXTRACT(YEAR FROM TO_TIMESTAMP(hist.sold_date/1000)) = 2017 
    group by hist.product_id,pr.name,EXTRACT(day FROM TO_TIMESTAMP(hist.sold_date/1000)),o.name
    order by o.name,pr.name',
    'select d from generate_series(1,31) d') 
as ("proId" int ,product_name text,organizationName text,
"1-day" float,"2-day" float,"3-day" float,"4-day" float,"5-day" float,"6-day" float
,"7-day" float,"8-day" float,"9-day" float,"10-day" float,"11-day" float,"12-day" float,"13-day" float,"14-day" float,"15-day" float,"16-day" float,"17-day" float
,"18-day" float,"19-day" float,"20-day" float,"21-day" float,"22-day" float,"23-day" float,"24-day" float,"25-day" float,"26-day" float,"27-day" float,"28-day" float,
"29-day" float,"30-day" float,"31-day" float);

请注意,使用PostgreSQL Crosstab查询。我使用coalesce来处理空值(交叉表查询显示" 0"当有空数据返回时)。

答案 1 :(得分:1)

以下查询将有助于找到相同的内容:

select o.name,
       p.name,
       sum(case when extract (day from to_timestamp(sold_date))=1 then sold_stock else 0 end)day1_sold_stock,
       sum(case when extract (day from to_timestamp(sold_date))=2 then sold_stock else 0 end)day2_sold_stock,
       sum(case when extract (day from to_timestamp(sold_date))=3 then sold_stock else 0 end)day3_sold_stock,      
from sales_order so,
    organization o,
    product p
where so.organization_id=o.id
and so.product_id=p.id
group by o.name,
       p.name;

我只提供了3天的逻辑,你可以在剩下的时间里实现相同的目标。

基本上首先对id进行基本连接,然后检查每个日期(在将epoch转换为时间戳然后提取日期之后)。

答案 2 :(得分:1)

这里有几个选项,但首先要了解这些限制很重要。

最大的限制是规划人员需要在规划阶段之前知道记录大小,因此必须明确定义,而不是动态定义。有各种方法来解决这个问题。在一天结束的时候,你可能会像Bavesh的回答一样,但有一些工具可能会有所帮助。

其次,您可能希望在加入三个表然后转动的简单查询中按日期汇总。

对于第二种方法,您可以:

  1. 您可以执行简单查询,然后将数据拉入Excel或类似内容,并在那里创建数据透视表。这可能是最简单的解决方案。
  2. 您可以使用tablefunc扩展名为您创建交叉表。
  3. 然后我们遇到第一个问题,即如果你总是做30天,那么如果你很乏味则很容易。但是,如果你想每天做一个月,你会遇到行长问题。在这里你可以做的是在函数(pl / pgsql)中创建一个动态查询并返回一个refcursor。在这种情况下,实际计划发生在功能中,计划员不需要在外层担心。然后在输出上调用FETCH