2017-02-13 1 views
1

У меня есть проект по CRM, который поддерживает заказ на продажу продукции для каждой организации.Postgresql запрос на каждый день проданного количества акций

Я хочу посчитать каждый день проданный запас, который мне удалось сделать, перейдя по дате, но, очевидно, это смехотворный метод и занимает больше времени и памяти.

Пожалуйста, помогите мне разобраться в одном запросе. Является ли это возможным?

Это моя структура базы данных для вашей справки.

продукт: ID (PK), имя

организация: ID (PK), имя

sales_order: ID (PK), product_id (FK), organization_id (ФК) , 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 для обработки нулевых значений (Crosstab Query для отображения «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, а затем проверяют, есть ли каждая дата (после преобразования эпохи в метку времени, а затем извлечения дня).

+0

Работает, но замедляет запрос. Какие-либо предложения? –

1

У вас есть несколько вариантов здесь, но важно сначала понять ограничения.

Большое ограничение заключается в том, что планировщик должен знать размер записи до этапа планирования, поэтому это должно быть явно определено, а не динамически определено. Есть разные способы обойти это. В конце концов, вы, вероятно, будете иметь что-то похожее на ответ Бэвеша, но есть некоторые инструменты, которые могут помочь.

Во-вторых, вы можете захотеть агрегировать по дате в простой запрос, соединяющий три таблицы, а затем поворачивать.

Для второго подхода, вы можете:

  1. Вы можете сделать простой запрос, а затем извлекать данные в Excel или аналогичные и создать сводную таблицу там. Это, наверное, самое простое решение.
  2. Вы можете использовать расширение tablefunc для создания кросс-таблицы для вас.

Тогда мы доберемся до первой проблемы, которая заключается в том, что если вы всегда делаете 30 дней, то это легко, если утомительно. Но если вы хотите делать каждый день в течение месяца, вы сталкиваетесь с проблемой длины строки. Здесь вы можете создать динамический запрос в функции (pl/pgsql) и вернуть refcursor. В этом случае фактическое планирование происходит в функции, и планировщику не нужно беспокоиться об этом на внешнем уровне.Затем вы вызываете FETCH на выходе.

Смежные вопросы