postgresql - 如何在 BETWEEN 子句中插入 AVG?

标签 postgresql subquery case average window-functions

例如,以 Northwind 为例。我想使用 CASE 子句通过将 units_in_stock 与其 AVG 值进行比较来创建类别,并将该值放入多个 BETWEEN 中> 条款。这就是我所得到的:

    SELECT product_name, unit_price, units_in_stock,
        CASE
            WHEN units_in_stock > (SELECT AVG(units_in_stock) + 10 FROM products) THEN 'many'
            WHEN units_in_stock BETWEEN (SELECT AVG(units_in_stock) - 10 FROM products) AND (SELECT AVG(units_in_stock) + 10 FROM products) THEN 'average'
            ELSE 'low'
        END AS amount
    FROM products
    ORDER BY units_in_stock;

根据pgAdmin中的分析工具AVG(units_in_stock)计算了3次。有没有办法减少计算量?

最佳答案

您可以使用窗口函数代替子查询。此外,在第二个 WHEN 条件中无需使用 BETWEEN;大于平均值 + 10 的值由第一个分支处理,并且永远不会到达第二个分支。

我将其表述为:

SELECT product_name, unit_price, units_in_stock,
    CASE
        WHEN units_in_stock >  AVG(units_in_stock) OVER() + 10 THEN 'many'
        WHEN units_in_stock >= AVG(units_in_stock) OVER() - 10 THEN 'average'
        ELSE 'low'
    END AS amount
FROM products
ORDER BY units_in_stock;

我希望数据库能够优化查询,以便窗口平均值仅计算一次。如果不是这种情况,另一种方法是首先计算子查询中的平均值:

SELECT product_name, unit_price, units_in_stock,
    CASE
        WHEN units_in_stock >  avg_units_in_stock + 10 THEN 'many'
        WHEN units_in_stock >= avg_units_in_stock - 10 THEN 'average'
        ELSE 'low'
    END AS amount
FROM (SELECT p.*, AVG(units_in_stock) OVER() avg_units_in_stock FROM products p) p
ORDER BY units_in_stock;

关于postgresql - 如何在 BETWEEN 子句中插入 AVG?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64195479/

相关文章:

mysql - PostgreSQL 转换日期 (YYYY-WW) 与 MySQL ('%x-%v' )

MySQL不划分列

ssl - Websphere MQ Explorer SSL 字段 "Accept only certificates with Distinguished Names matching these values field"是否区分大小写?

java - 比较 ArrayList 中的字符串。区分大小写

postgresql - 通过触发器强制执行行不变性

ruby-on-rails - Rails 网页有一个重定向循环 ERR_TOO_MANY_REDIRECTS

ruby-on-rails - 英雄联盟 : Postgres - could not connect to server: Connection refused

php - Mysql - 如果值不存在,则使用另一个表

Mysql - 按返回零进行计数和分组

mysql - 如何使用 CASE 根据其他属性更新 mysql 中的两个属性