窗口函数的SQL条件
我想对我的数据库(PostgreSQL v9.4.5)执行一个特殊请求,但我没有做到这一点 为了简单起见,假设我有下表,代表不同城市的不同平均温度,并根据不同的时间长度(以月为单位)进行计算: 我可以这样做:窗口函数的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
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
;