【问题标题】:AVG function with multiple conditions and columns in SQL LiteSQLite中具有多个条件和列的AVG函数
【发布时间】:2019-08-08 07:20:57
【问题描述】:

我想出了如何使用 condition/s 执行 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

我想为产品 C12 计算一个名为 sales_index_goal 的新值。那么,这个值的公式是:

产品'C12'Goal_Met = 'Y'sales_indexsub_productsales_indexGoal_Met = 'N' 在之前的销售期间的平均值。

例如,如果我想为 sales_period 0003 计算产品 'C12' 的 sales_index_goal,它将计算为:

(30,20,15) 的平均值,其中3020 是产品'C12' 在销售期间'C12'sales_indexes 1 和@9876543440@ 和@9876 @是产品'F20'在销售期间2sales_index

我在计算确切销售期间的这个值时没有任何问题。但是,我很难想出一个查询来计算所有销售期间产品'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(有关它不起作用的更详细原因在我在答案下方的评论中) 可以看到查询产品F20here的结果

【问题讨论】:

    标签: sql sqlite conditional average


    【解决方案1】:

    使用窗口函数是一个很好的起点。一个问题在于,您希望对来自不同列的值进行平均,这可能具有不同的出现次数。

    我认为您需要分解计算以计算平均值:将值相加,然后将其除以出现次数的总和。

    考虑:

    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 中,使用您的示例数据返回:

    | 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 |
    

    【讨论】:

    • 您好,感谢您的回答。这主要是有效的,但有一个问题。想象一下,我正在尝试计算销售期 0003 中 F20 而不是 C12 的 sales_index_goal 值。返回值应该是 30,因为只有一次出现 (F20 和 Y) 或 (C12 和 N)。但是,在 C12 的目标满足 = Y 的情况下,代码不会返回 C12 和 N 的 0,而是返回 C12 的 product_sub 的销售索引。因此它返回期间 0001 中的 D71 和期间 0002 中的 C05 的销售索引。任何想法为什么会这样?
    • 其实第二种情况下C12的sales_index_goal应该是17.5而不是20,不知道算不算是0001期产品C05的sales_index。
    【解决方案2】:

    不确定这是否真的需要窗口函数。

    下面的示例只是按 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
    
    产品ID |销售期 |销售数量 |销售指数 |产品_sub |目标满足 |销售指数 :--------- | :----------- | :-------- | :------------ | :------------ | :------- | :---------- C12 | 0001 | 15 | 20 | D71 |是 | C12 | 0002 | 15 | 30 | C05 |是 | 15 C12 | 0002 | 15 | 30 | C05 |是 | 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;
    
    产品ID |销售期 |销售数量 |销售指数 |产品_sub |目标满足 | sales_index_goal :--------- | :----------- | :-------- | :------------ | :------------ | :------- | :--------------- C12 | 0001 | 15 | 20 | D71 |是 | C12 | 0002 | 15 | 30 | C05 |是 | 17.5 C12 | 0003 | 05 | 04 | F20 | N | 21.7

    db小提琴here

    【讨论】:

    • 您好,感谢您抽出宝贵时间回答,但销售期 0003 以外的值不是我想要的。第一个周期的值应该是 NULL,第二个周期的值应该是 17.5
    • @memokerobi 只是将&lt;= 更改为&lt; 似乎已经解决了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多