窗口函数的SQL条件

窗口函数的SQL条件,sql,postgresql,window-functions,Sql,Postgresql,Window Functions,我想对我的数据库(PostgreSQL v9.4.5)执行一个特殊请求,但我没有做到这一点 为了简单起见,假设我有下表,代表不同城市的不同平均温度,并根据不同的时间长度(以月为单位)进行计算: 我可以这样做: SELECT * FROM AvgTemperatures WHERE MIN(avg) OVER (PARTITION BY city) > 16 但是: 此外,我不能使用分组方式,如: SELECT * FROM AvtTemperatures GROUP BY c

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

为了简单起见,假设我有下表,代表不同城市的不同平均温度,并根据不同的时间长度(以月为单位)进行计算:

我可以这样做:

 SELECT *
 FROM AvgTemperatures
 WHERE MIN(avg) OVER (PARTITION BY city) > 16
但是:

此外,我不能使用
分组方式
,如:

 SELECT *
 FROM AvtTemperatures
 GROUP BY city
 HAVING MIN(avg) > 16
因为我将由于聚合而丢失信息(顺便说一句,由于“SELECT*”,此查询无效)

我很确定我可以使用
OVER PARTITION BY
来解决这个问题,但我不知道如何解决。有人有想法吗?

“一次执行所有操作”是指同一操作中的所有表达式 逻辑查询过程阶段同时进行逻辑计算

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

假设你有:

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;
所有一次性操作告诉我们这两个条件在同一时间点进行逻辑计算。因此,SQL Server可以 根据下列条件按任意顺序计算WHERE子句中的条件: 估计执行计划。所以这里的主要问题是什么条件 首先评估

案例1:

如果(Id=1002)是第一个,那么如果(ROW_NUMBER()超过(ORDER BY Id)=1)

结果:1002

案例2:

If(ROW_NUMBER()OVER(ORDER BY Id)=1),然后检查是否(Id=1002)

结果:空

所以我们有一个悖论。

这个例子说明了为什么我们不能在WHERE子句中使用窗口函数。 您可以对此进行更多思考,并找到为什么窗口函数是 允许仅在选择按顺序子句中使用

要获得所需内容,您可以使用
CTE/subquery
包装窗口函数,如下所示:

 SELECT *
 FROM AvtTemperatures
 GROUP BY city
 HAVING MIN(avg) > 16

输出:

╔═════╦══════════╦═════╦═════════╗
║ 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   ║
╚═════╩══════════╩═════╩═════════╝

您需要将其包装在派生表中,以便能够在where子句中使用:

select *
from (
  SELECT t.*, MIN(avg) OVER (PARTITION BY city) as city_avg
  FROM AvgTemperatures t
) x
WHERE city_avg > 16

使用子查询获取最大值,然后使用
,其中

select t.*
from (select t.*, max(avg) over (partition by city) as maxavg
      from avgTemperatures t
     ) t
where maxavg > 19;
另一种方法是在
where
子句中执行此操作:

select t.*
from avgTemperatures t
where t.city in (select t2.city from avgTemperatures t2 where t2.avg > 19);

最简单的解决方案是使用

测试表:

create table avttemperatures (
    id int, city text, avg int, months int
);
insert into avttemperatures (id, city, avg, months) values
(  1,'New-York',20,3),
(  2,'New-York',19,6),
(  3,'New-York',15,12),
(  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);

如果您只想知道是否至少存在一个,则无需聚合:


注意:
avg
对于一个列来说是个坏名字。

@a_horse_with_no_name这是SQL Server的例子,但请解释为什么不能在
WHERE
子句中使用窗口函数
select t.*
from (select t.*, max(avg) over (partition by city) as maxavg
      from avgTemperatures t
     ) t
where maxavg > 19;
select t.*
from avgTemperatures t
where t.city in (select t2.city from avgTemperatures t2 where t2.avg > 19);
select id, city, avg, months
from avttemperatures
where city in (
    select city
    from avttemperatures
    group by 1
    having bool_or(avg > 19)
)
order by  2, 4
;
 id |   city   | avg | months 
----+----------+-----+--------
 11 | Miami    |  28 |      1
 12 | Miami    |  25 |      4
 13 | Miami    |  21 |     12
 14 | Miami    |  22 |     15
 15 | Miami    |  20 |     24
  1 | New-York |  20 |      3
  2 | New-York |  19 |      6
  3 | New-York |  15 |     12
  4 | New-York |  15 |     24
create table avttemperatures (
    id int, city text, avg int, months int
);
insert into avttemperatures (id, city, avg, months) values
(  1,'New-York',20,3),
(  2,'New-York',19,6),
(  3,'New-York',15,12),
(  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);
SELECT id, city, avg, months
FROM avgtemperatures t
WHERE EXISTS ( SELECT 42
    FROM avgtemperatures x
    WHERE x.city = t.city
    AND x.avg > 19
    )
ORDER BY city,months DESC
   ;