使用FIRST_VALUE而不包括group by中的内部列

问题描述 投票:1回答:4

我使用的表看起来像这样:

userID, eventDate, eventName
1  2019-01-01  buySoup
2  2019-01-01  buyEggs
2  2019-01-03  buyMilk
2  2019-01-04  buyMilk
3  2019-01-02  buyBread
3  2019-01-03  buyBread

我目前的查询是:

SELECT
    userID,
    FIRST_VALUE(eventName) OVER (
        PARTITION BY userID ORDER BY eventDate ASC
    ) AS firstBought 
FROM table 
GROUP BY userID

我觉得这应该回归:

userID, firstBought
1  buySoup
2  buyEggs
3  buyBread

相反,它给出了错误:

'错误:列“table.eventName”必须出现在GROUP BY子句中或用于聚合函数中

有没有办法获取此值而不将其包含在按功能分组或创建子查询?我正在使用PostgreSQL。

如果我将它包含在group by子句中,则返回

userID, firstBought
1  buySoup
2  buyEggs
2  buyEggs
2  buyEggs
3  buyBread
3  buyBread

我知道我可以使它成为子查询,然后按userID,firstBought进行分组,但我宁愿不创建另一个子查询。

sql postgresql vertica
4个回答
2
投票

而不是group by,使用select distinct

select distinct userID,
       FIRST_VALUE(eventName) over (partition by userID order by eventDate ASC) as firstBought 
from table ;

或者,您可以使用数组:

select userId,
       (array_agg(eventName order by eventDate))[1] as firstBought
from table
group by userId;

Postgres没有“第一”聚合功能,但这种方法效果很好。


1
投票

我同意A. Saunders。

你需要一个外部查询。

除了SELECT DISTINCT(实际上归结为SELECT列表的所有列的GROUP BY)之外,您不能将OLAP和GROUP BY函数混合到同一个SELECT中。

所以,如果你有MAX(),你必须:

WITH -- your input data ...
input(userID,eventDate,eventName) AS (
          SELECT 1,DATE '2019-01-01','buySoup'
UNION ALL SELECT 2,DATE '2019-01-01','buyEggs'
UNION ALL SELECT 2,DATE '2019-01-03','buyMilk'
UNION ALL SELECT 2,DATE '2019-01-04','buyMilk'
UNION ALL SELECT 3,DATE '2019-01-02','buyBread'
UNION ALL SELECT 3,DATE '2019-01-03','buyBread'
)
,
getfirstbought AS (
  SELECT 
    userid
  , eventdate
  , FIRST_VALUE(eventname) OVER (
      PARTITION BY userid ORDER BY eventdate
   ) AS firstbought
  FROM input
)
SELECT
  userid
, firstbought
, MAX(eventdate) AS maxdt
FROM getfirstbought
GROUP BY 1,2;
-- out  userid | firstbought |   maxdt    
-- out --------+-------------+------------
-- out       2 | buyEggs     | 2019-01-04
-- out       3 | buyBread    | 2019-01-03
-- out       1 | buySoup     | 2019-01-01
-- out (3 rows)
-- out 
-- out Time: First fetch (3 rows): 22.157 ms. All rows formatted: 22.208 ms

0
投票

我猜PostgreSQL的DISTINCT ON可以做到这一点:

SELECT DISTINCT ON (userid)
       userid, eventdate, eventname
FROM "table"
ORDER BY (eventdate);

这将给你每userid的行与最小eventdate


0
投票

FIRST_VALUE不是一个集合函数。它是一个分析窗函数。所以你的基本查询不需要GROUP BY子句。它应该重写为:

SELECT 
        userID,
        FIRST_VALUE(eventName) over (PARTITION BY userID ORDER BY eventDate ASC) AS firstBought
FROM table;

从上面的一条评论中可以看出,您正在使用的其他功能包括MAX等聚合函数。要完成您要执行的操作,您需要将上述查询用作子查询。这将允许您使用聚合函数并从基本查询中获取唯一值。查询看起来像这样(我添加了一个价格列作为例子)。

SELECT userID, firstBought, MAX(price)
FROM (
        SELECT userID, price, FIRST_VALUE(eventName) over (partition by userID order by eventDate ASC) as firstBought 
        from test
) x
GROUP BY userId, firstBought;

这应该做的伎俩!您可以在外部查询上使用其他聚合函数,并在子查询中使用其他窗口函数。

© www.soinside.com 2019 - 2024. All rights reserved.