Функция AVG с несколькими условиями и столбцами в SQL Lite - PullRequest
1 голос
/ 18 марта 2019

Я понял, как выполнить функцию avg с условием / с, но не смог заставить ее работать для моей конкретной потребности. Допустим, я работаю с этой таблицей под названием sales_performance

  product_ID  sales_period  sales_qty  sales_index  product_sub goal_met
         C12          0001         15           20          D71        Y
         D71          0001         07           09          C12        N
         F20          0001         25           30          C05        Y
         C05          0001         10           15          F20        N
         C12          0002         15           30          C05        Y
         C05          0002         12           06          C12        N
         D71          0002         30           20          F20        Y
         F20          0002         20           15          D71        N
         C12          0003         05           04          F20        N
         F20          0003         40           35          C12        Y
         D71          0003         20           20          C05        Y
         C05          0003         12           10          D71        N

Я хочу рассчитать новое значение с именем sales_index_goal для продукта C12. Тогда формула для этого значения будет:

среднее значение sales_index продукта 'C12' при Goal_Met = 'Y' и sales_index его sub_product при Goal_Met = 'N' в периоды продаж до этого.

Так, например, если бы я хотел вычислить sales_index_goal для продукта 'C12' для sales_period 0003, он был бы рассчитан как:

среднее значение (30, 20, 15), где 30 и 20 - это sales_index es продукта 'C12' в периоды продаж 1 и 2 и 15 это sales_index продукта 'F20' в период продаж 2.

У меня нет проблем с вычислением этого значения для точных периодов продаж. Однако мне трудно найти запрос, который вычисляет это значение для продукта 'C12' для всех периодов продаж. В настоящее время я написал этот запрос, который не работает:

SELECT 
    s.*, 
    AVG(CASE 
        WHEN s2.goal_met = "Y" AND s2.product_id = "C2" 
            THEN s2.sales_index 
        WHEN s2.product_id = (
            SELECT s2.product_sub WHERE s2.product_id = "C12"
        ) AND s2.goals_met = "N" 
            THEN s2.sales_index
        ELSE NULL 
    END)
    OVER (
        ORDER BY s.sales_period 
        ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
    ) AS sales_index_goal
FROM 
    sales_performance s, 
    sales_performance s2
WHERE s.product_id = "C12" 

Я был бы очень признателен за любую помощь в этом. Бонус: вычисление этого значения для всех продуктов за все периоды продаж.

Редактировать: приведенный ниже ответ хорошо подходит для расчета sales_index_goal для продукта C12, однако он не работает для продукта F20 (более подробная причина того, почему он не работает, приведена в моем комментарии ниже ответа) Вы можете увидеть результат запроса для продукта F20 здесь

Ответы [ 2 ]

2 голосов
/ 18 марта 2019

Использование оконной функции - хорошее место для начала. Одна проблема заключается в том, что вы хотите усреднить значения, полученные из разных столбцов, и у которых может быть разное количество вхождений.

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

Рассмотрим:

SELECT *
FROM (
    SELECT 
        s.*,
        (
            0.0 + 
            COALESCE(SUM(CASE WHEN goal_met = 'Y' THEN sales_index END) OVER(
                PARTITION BY product_id 
                ORDER BY sales_period 
                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ), 0)
            + COALESCE(SUM(CASE WHEN goal_met = 'N' THEN sales_index END) OVER(
                PARTITION BY product_sub 
                ORDER BY sales_period 
                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ), 0)
        ) / (
            COALESCE(SUM(goal_met = 'Y') OVER(
                PARTITION BY product_id 
                ORDER BY sales_period 
                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ), 0)
            + COALESCE(SUM(goal_met = 'N') OVER(
                PARTITION BY product_sub 
                ORDER BY sales_period 
                ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ), 0)
        ) AS sales_index_goal
    FROM sales_performance s
) x WHERE product_ID = 'C12'

В эта скрипта БД , с вашими данными выборки, это возвращает:

| product_ID | sales_period | sales_qty | sales_index | product_sub | goal_met | sales_index_goal   |
| ---------- | ------------ | --------- | ----------- | ----------- | -------- | ------------------ |
| C12        | 1            | 15        | 20          | D71         | Y        |                    |
| C12        | 2            | 15        | 30          | C05         | Y        | 20                 |
| C12        | 3            | 5         | 4           | F20         | N        | 21.666666666666668 |
1 голос
/ 18 марта 2019

Не уверен, что для этого нужны оконные функции.

Приведенный ниже пример просто сам связывает таблицу и группы по продуктам C12.

CREATE TABLE sales_performance
(
 product_ID varchar(3) not null,
 sales_period varchar(4) not null,
 sales_qty char(2) not null,
 sales_index char(2) not null,
 product_sub char(3) not null,
 goal_met char(1)  not null,
 PRIMARY KEY (product_ID, sales_period)
)
INSERT INTO sales_performance
(product_ID,sales_period,sales_qty,sales_index,product_sub,goal_met) 
VALUES
 ('C12','0001','15','20','D71','Y')
,('D71','0001','07','09','C12','N')
,('F20','0001','25','30','C05','Y')
,('C05','0001','10','15','F20','N')
,('C12','0002','15','30','C05','Y')
,('C05','0002','12','06','C12','N')
,('D71','0002','30','20','F20','Y')
,('F20','0002','20','15','D71','N')
,('C12','0003','05','04','F20','N')
,('F20','0003','40','35','C12','Y')
,('D71','0003','20','20','C05','Y')
,('C05','0003','12','10','D71','N')
;
SELECT c12.*, sub.sales_index
FROM sales_performance c12
LEFT JOIN sales_performance sub 
  ON sub.sales_period < c12.sales_period 
 AND 
 (
    (sub.product_ID = c12.product_sub AND sub.goal_met = 'N') OR
    (sub.product_ID = c12.product_ID AND sub.goal_met = 'Y')
 )
WHERE c12.product_id = 'C12'
ORDER BY c12.product_ID, c12.sales_period, sub.product_ID
product_ID | sales_period | sales_qty | sales_index | product_sub | goal_met | sales_index
:--------- | :----------- | :-------- | :---------- | :---------- | :------- | :----------
C12        | 0001         | 15        | 20          | D71         | Y        | <em>null</em>       
C12        | 0002         | 15        | 30          | C05         | Y        | 15         
C12        | 0002         | 15        | 30          | C05         | Y        | 20         
C12        | 0003         | 05        | 04          | F20         | N        | 20         
C12        | 0003         | 05        | 04          | F20         | N        | 30         
C12        | 0003         | 05        | 04          | F20         | N        | 15         
SELECT 
 c12.*
 , ROUND(AVG(sub.sales_index),1) AS sales_index_goal
FROM sales_performance c12
LEFT JOIN sales_performance sub 
  ON sub.sales_period < c12.sales_period 
 AND 
 (
    (sub.product_ID = c12.product_sub AND sub.goal_met = 'N') OR
    (sub.product_ID = c12.product_ID AND sub.goal_met = 'Y')
 )
WHERE c12.product_id = 'C12' 
GROUP BY c12.product_ID, c12.sales_period
ORDER BY c12.product_ID, c12.sales_period;
product_ID | sales_period | sales_qty | sales_index | product_sub | goal_met | sales_index_goal
:--------- | :----------- | :-------- | :---------- | :---------- | :------- | :---------------
C12        | 0001         | 15        | 20          | D71         | Y        | <em>null</em>            
C12        | 0002         | 15        | 30          | C05         | Y        | 17.5            
C12        | 0003         | 05        | 04          | F20         | N        | 21.7            

db <> скрипка здесь

...