窗口函数的SQL条件

Edo*_*the 4 sql postgresql window-functions

我想对我的数据库(PostgreSQL v9.4.5)做一个特殊的请求,但我没有设法做到这一点.

简单来说,假设我有下表AvgTemperatures,表示不同城市的不同平均温度,并根据不同的时间长度计算(以月计):

 id |   city    |  avg | months 
----+-----------+------+--------
  1 |  New-York |   20 |     3   <--- average temperate over the last 3 months
  2 |  New-York |   19 |     6   <--- average temperate over the last 6 months
  3 |  New-York |   15 |    12   <--- etc
  4 |  New-York |   15 |    24
  5 |    Boston |   13 |     3
  6 |    Boston |   18 |     8
  7 |    Boston |   17 |    12
  8 |    Boston |   16 |    15
  9 |   Chicago |   12 |     2
 10 |   Chicago |   14 |    12
 11 |     Miami |   28 |     1
 12 |     Miami |   25 |     4
 13 |     Miami |   21 |    12
 14 |     Miami |   22 |    15
 15 |     Miami |   20 |    24
Run Code Online (Sandbox Code Playgroud)

现在,想象一下,我想选择一个城市中至少有一个平均值超过19度的措施的所有行.在这种情况下,我想:

 id |   city    |  avg | months 
----+-----------+------+--------
  1 |  New-York |   20 |     3  
  2 |  New-York |   19 |     6  
  3 |  New-York |   15 |    12  
  4 |  New-York |   15 |    24  
 11 |     Miami |   28 |     1  
 12 |     Miami |   25 |     4  
 13 |     Miami |   21 |    12  
 14 |     Miami |   22 |    15  
 15 |     Miami |   20 |    24  
Run Code Online (Sandbox Code Playgroud)

我可以这样做:

 SELECT *
 FROM AvgTemperatures
 WHERE MIN(avg) OVER (PARTITION BY city) > 16
Run Code Online (Sandbox Code Playgroud)

但是:

********** Erreur **********

ERROR: window functions not allowed in WHERE clause
Run Code Online (Sandbox Code Playgroud)

更重要的是,我不能GROUP BY像以下那样使用:

 SELECT *
 FROM AvtTemperatures
 GROUP BY city
 HAVING MIN(avg) > 16
Run Code Online (Sandbox Code Playgroud)

因为我会因聚合而丢失信息(因为"SELECT*"因此查询无效).

我很确定我可以用它OVER PARTITION BY来解决这个问题,但我不知道怎么做.有人有想法吗?

Luk*_*zda 6

首先,它被称为 all-at-once operation

"一次性操作"意味着同一逻辑查询处理阶段中的所有表达式在逻辑上同时进行评估.

伟大章节对窗口功能的影响:

假设你有:

CREATE TABLE Test ( Id INT) ;

INSERT  INTO Test VALUES  ( 1001 ), ( 1002 ) ;

SELECT Id
FROM Test
WHERE Id = 1002
  AND ROW_NUMBER() OVER(ORDER BY Id) = 1;
Run Code Online (Sandbox Code Playgroud)

All-at-Once操作告诉我们在同一时间点逻辑评估这两个条件.因此,SQL Server可以根据估计的执行计划以任意顺序评估WHERE子句中的条件.所以这里的主要问题是哪个条件首先评估.

情况1:

If ( Id = 1002 ) is first, then if ( ROW_NUMBER() OVER(ORDER BY Id) = 1 )

结果:1002

案例2:

If ( ROW_NUMBER() OVER(ORDER BY Id) = 1 ), then check if ( Id = 1002 )

结果:空

所以我们有一个悖论.

此示例说明了为什么我们不能在WHERE子句中使用Window Functions.您可以更多地考虑这一点,并找到为什么允许在SELECTORDER BY子句中使用Window Functions !

为了得到你想要的你可以用窗口函数什么CTE/subquery作为戈登的回答:

;WITH cte AS
(
  SELECT t.*, MAX(AVG) OVER (PARTITION BY city) AS average
  FROM avgTemperatures t
)
SELECT *
FROM cte
where average > 19
ORDER BY id;
Run Code Online (Sandbox Code Playgroud)

LiveDemo

输出:

??????????????????????????????????
? id  ?   city   ? avg ? months  ?
??????????????????????????????????
?   1 ? New-York ?  20 ?     3   ?
?   2 ? New-York ?  19 ?     6   ?
?   3 ? New-York ?  15 ?    12   ?
?   4 ? New-York ?  15 ?    24   ?
?  11 ? Miami    ?  28 ?     1   ?
?  12 ? Miami    ?  25 ?     4   ?
?  13 ? Miami    ?  21 ?    12   ?
?  14 ? Miami    ?  22 ?    15   ?
?  15 ? Miami    ?  20 ?    24   ?
??????????????????????????????????
Run Code Online (Sandbox Code Playgroud)