2017-02-13 112 views
1

我有CRM项目,维护每个组织的产品销售订单。Postgresql查询每天销售库存数

我想统计每日售出的股票,我已经设法通过日期循环来完成,但显然这是一种荒谬的方法,需要更多的时间和记忆。

请帮我找出它在单个查询。可能吗?

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

产品: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

+0

你为什么要把时间戳存为bigint? '时间戳'将更容易处理 –

回答

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

下面的查询将有助于找到相同:

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转换为时间戳并提取日期之后)。

+0

Works,但会减慢查询速度。有什么建议么? –

1

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

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

其次,您可能希望按照日期汇总加入三个表格的简单查询,然后进行透视。

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

  1. 你可以做一个简单的查询,然后将数据拉成Excel或类似,并创建一个数据透视表存在。这可能是最简单的解决方案。
  2. 您可以使用tablefunc扩展名为您创建交叉表。

然后我们遇到第一个问题,就是如果你总是在做30天,那么很简单,如果单调乏味。但是如果你想每天做一个月,你会遇到行长问题。在这里你可以做的是在一个函数(pl/pgsql)中创建一个动态查询并返回一个refcursor。在这种情况下,实际的计划是在功能中进行的,计划者不需要担心外部层面的问题。然后您在输出上拨打FETCH