我正在努力选择第一个&基于月份和时间的窗口中的最后日期提供的年份。
以下是示例数据:
F.rates
| id | c_id | date | rate |
---------------------------------
| 1 | 1 | 01-01-1991 | 1 |
| 1 | 1 | 15-01-1991 | 0.5 |
| 1 | 1 | 30-01-1991 | 2 |
.................................
| 1 | 1 | 01-11-2014 | 1 |
| 1 | 1 | 15-11-2014 | 0.5 |
| 1 | 1 | 30-11-2014 | 2 |
这是我提出的pgSQL SELECT:
SELECT c_id, first_value(date) OVER w, last_value(date) OVER w FROM F.rates
WINDOW w AS (PARTITION BY EXTRACT(YEAR FROM date), EXTRACT(MONTH FROM date), c_id
ORDER BY date ASC)
这给了我一个非常接近我想要的结果:
| c_id | first_date | last_date |
----------------------------------
| 1 | 01-01-1991 | 15-01-1991 |
| 1 | 01-01-1991 | 30-01-1991 |
.................................
应该是:
| c_id | first_date | last_date |
----------------------------------
| 1 | 01-01-1991 | 30-01-1991 |
.................................
由于某些原因last_value(date)
返回窗口中的每条记录。这让我觉得我误解了SQL中的窗口是如何工作的。这就像SQL为它迭代的每一行形成一个新窗口,而不是基于YEAR和MONTH的整个表的多个窗口。
任何人都可以善良并解释我是否错了,我如何达到我想要的结果?
我之所以没有在GROUP BY子句中使用MAX / MIN,是有原因的。我的下一步是检索我选择的日期的相关费率,例如:
| c_id | first_date | last_date | first_rate | last_rate | avg rate |
-----------------------------------------------------------------------
| 1 | 01-01-1991 | 30-01-1991 | 1 | 2 | 1.1 |
.......................................................................
答案 0 :(得分:2)
如果您希望将输出分组为单个(或更少)行,则应使用简单聚合(即GROUP BY
),如果avg_rate
足够:
SELECT c_id, min(date), max(date), avg(rate)
FROM F.rates
GROUP BY c_id, date_trunc('month', date)
有关PostgreSQL's documentation中的窗口函数的更多信息:
但与常规聚合函数不同,使用窗口函数不会导致行被分组到单个输出行中 - 行保留其独立的标识。
...
还有另一个与窗口函数相关的重要概念:对于每一行,其分区中都有一组称为窗口框架的行。许多(但不是全部)窗口函数仅作用于窗口框架的行,而不是整个分区。 默认情况下,如果提供了
ORDER BY
,则该框架包含分区的所有行 到当前行 ,以及根据ORDER BY
子句等于当前行的任何后续行。省略ORDER BY
时,默认框架由分区中的所有行组成。...
可以选择以其他方式定义窗口框架...有关详细信息,请参阅Section 4.2.8。
修改强>:
如果您要折叠(最小/最大聚合)您的数据并希望收集的列数多于GROUP BY
中列出的列数,则您有两个选择:
在子查询中选择最小/最大值,然后将其原始行连接起来(但是这样,你必须处理这样一个事实,即min / max-ed列通常不是唯一的) :
SELECT c_id,
min first_date,
max last_date,
first.rate first_rate,
last.rate last_rate,
avg avg_rate
FROM (SELECT c_id, min(date), max(date), avg(rate)
FROM F.rates
GROUP BY c_id, date_trunc('month', date)) agg
JOIN F.rates first ON agg.c_id = first.c_id AND agg.min = first.date
JOIN F.rates last ON agg.c_id = last.c_id AND agg.max = last.date
DISTINCT ON
DISTINCT ON
通常用于此任务,但高度依赖于排序(一次只能以这种方式搜索1个极值):
SELECT DISTINCT ON (c_id, date_trunc('month', date))
c_id,
date first_date,
rate first_rate
FROM F.rates
ORDER BY c_id, date
您可以将此查询与F.rates
的其他聚合子查询相关联,但这一点(如果您确实需要最小和最大,在您的情况下甚至是平均值),SQL兼容的方式更适合
答案 1 :(得分:1)
窗口函数不适用于此。改为使用聚合函数。
select
c_id, date_trunc('month', date)::date,
min(date) first_date, max(date) last_date
from rates
group by c_id, date_trunc('month', date)::date;
c_id | date_trunc | first_date | last_date ------+------------+------------+------------ 1 | 2014-11-01 | 2014-11-01 | 2014-11-30 1 | 1991-01-01 | 1991-01-01 | 1991-01-30
create table rates (
id integer not null,
c_id integer not null,
date date not null,
rate numeric(2, 1),
primary key (id, c_id, date)
);
insert into rates values
(1, 1, '1991-01-01', 1),
(1, 1, '1991-01-15', 0.5),
(1, 1, '1991-01-30', 2),
(1, 1, '2014-11-01', 1),
(1, 1, '2014-11-15', 0.5),
(1, 1, '2014-11-30', 2);