SQL Lite 中具有多个条件和列的 AVG 函数
AVG function with multiple conditions and columns in SQL Lite
我想出了如何使用 condition/s 执行 avg 函数,但我无法让它满足我的特定需求。
假设我正在使用这个名为 sales_performance
的 table
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
我想为产品 C12 计算一个名为 sales_index_goal 的新值。然后,此值的公式为:
average of sales_index
of product 'C12'
when Goal_Met = 'Y'
and the sales_index
of its sub_product
when Goal_Met = 'N'
during the sales periods before that one.
例如,如果我想为产品 'C12'
计算 sales_period
0003
的 sales_index_goal,它将计算为:
average of (30
,20
,15
) where 30
and 20
are the sales_index
es of product 'C12'
in sales periods 1
and 2
and 15
is the sales_index
of Product 'F20'
in sales period 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"
如果能提供任何帮助,我将不胜感激。奖励:为所有销售期间的所有产品计算此值。
编辑:下面的答案适用于计算产品 C12 的 sales_index_goal 但是,它不适用于产品 F20(为什么它不起作用的更详细原因在我在答案下方的评论中)
可以看到商品F20的查询结果here
使用 window 函数是一个很好的起点。一个问题在于您想要对来自不同列的值取平均值,并且这些值可能具有不同的出现次数。
我认为您需要分解计算以计算平均值:对值求和,然后除以出现次数的总和。
考虑:
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'
在 this DB fiddle 中,使用您的样本数据,这个 returns:
| 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 |
不确定这是否真的需要 window 功能。
下面的示例只是自链接 table 并按 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 | null
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 | null
C12 | 0002 | 15 | 30 | C05 | Y | 17.5
C12 | 0003 | 05 | 04 | F20 | N | 21.7
db<>fiddle here
我想出了如何使用 condition/s 执行 avg 函数,但我无法让它满足我的特定需求。 假设我正在使用这个名为 sales_performance
的 table 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
我想为产品 C12 计算一个名为 sales_index_goal 的新值。然后,此值的公式为:
average of
sales_index
of product'C12'
whenGoal_Met = 'Y'
and thesales_index
of itssub_product
whenGoal_Met = 'N'
during the sales periods before that one.
例如,如果我想为产品 'C12'
计算 sales_period
0003
的 sales_index_goal,它将计算为:
average of (
30
,20
,15
) where30
and20
are thesales_index
es of product'C12'
in sales periods1
and2
and15
is thesales_index
of Product'F20'
in sales period2
.
我在计算确切销售期间的这个值时没有遇到任何问题。但是,我很难想出一个查询来计算所有销售期间产品 '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"
如果能提供任何帮助,我将不胜感激。奖励:为所有销售期间的所有产品计算此值。
编辑:下面的答案适用于计算产品 C12 的 sales_index_goal 但是,它不适用于产品 F20(为什么它不起作用的更详细原因在我在答案下方的评论中) 可以看到商品F20的查询结果here
使用 window 函数是一个很好的起点。一个问题在于您想要对来自不同列的值取平均值,并且这些值可能具有不同的出现次数。
我认为您需要分解计算以计算平均值:对值求和,然后除以出现次数的总和。
考虑:
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'
在 this DB fiddle 中,使用您的样本数据,这个 returns:
| 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 |
不确定这是否真的需要 window 功能。
下面的示例只是自链接 table 并按 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 | null 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 | null C12 | 0002 | 15 | 30 | C05 | Y | 17.5 C12 | 0003 | 05 | 04 | F20 | N | 21.7
db<>fiddle here