窗口函数,用于选择Redshift Postgres中多数行的名称

时间:2017-10-02 22:32:17

标签: sql amazon-redshift window-functions

我有一个像这样的数据集,其中有些行很有用,但已损坏。

create table pages (
  page varchar,
  cat varchar,
  hits int
);

insert into pages values
(1, 'asdf', 1),
(1, 'fdsa', 2),
(1, 'Apples', 321),
(2, 'gwegr', 30),
(2, 'hsgsdf', 2),
(2, 'Bananas', 321);

我想知道每个页面的正确类别以及总点击次数。正确的类别是命中率最高的类别。 我想要一个像:

这样的数据集
page | category | sum_of_hits
-----------------------------
1    | Apples   |  324
2    | Bananas  |  353

我能得到的最远的是:

SELECT page,
       last_value(cat) over (partition BY page ORDER BY hits) as category,
       sum(hits) as sum_of_hits
FROM pages
GROUP BY 1, 2

但这是错误的:ERROR: column "pages.hits" must appear in the GROUP BY clause or be used in an aggregate function Position: 83

我尝试将命中汇总到一个聚合 - ORDER BY max(hits),但这没有意义,也不是我想要的。

小提琴:http://sqlfiddle.com/#!17/cb3c2/17

4 个答案:

答案 0 :(得分:1)

在派生表(FROM子句中的子查询)中使用窗口函数first_value()而不是hits的颠倒顺序:

select 
    page, 
    category,
    sum(hits) as sum_of_hits
from (
    select
        page,
        first_value(cat) over (partition by page order by hits desc) as category,
        hits
    from pages
    ) s
group by 1, 2
order by 1;

SqlFiddle.

答案 1 :(得分:1)

这里有两个问题:

首先是last_value的用法。请阅读Postgres documentation中有关最后一个值的说明:

  

请注意,first_value,last_value和nth_value仅考虑   "窗口框架内的行",默认情况下包含行   从分区的开始到当前的最后一个对等体   行。这可能会给nth_value和.n带来无益的结果   特别是last_value。您可以将框架重新定义为整体   通过在UNBOUNDED PRECEDING和UNBOUNDED之间添加ROWS进行分区   遵循OVER条款。有关更多信息,请参见第4.2.8节。

我建议您将其转换为first_value:

SELECT page,
       first_value(cat) over (partition BY page ORDER BY hits DESC) as category,
       hits
FROM pages

第二个问题是你不能直接在GROUP BY子句中使用window函数,你需要使用子查询或cte:

select page, category,
       sum(hits)
from (
SELECT page,
       first_value(cat) over (partition BY page ORDER BY hits DESC) as category,
       hits
FROM pages
) a
GROUP BY 1, 2

SQL Fiddle

答案 2 :(得分:0)

使用子查询:

{{1}}

答案 3 :(得分:0)

您似乎想要将命中总和放在最大值。这很容易:

select page, sum(hits) as total_hits,
       max(case when seqnum = 1 then category end) as category
from (select p.*,
             row_number() over (partition by page order by hits desc) as seqnum
      from pages p
     ) p
group by page;