使用FIRST_VALUE而不在分组依据中包括内部列

时间:2019-02-25 21:18:22

标签: sql postgresql vertica

我正在使用一个像这样的表:

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进行分组,首先购买,但我宁愿不创建另一个子查询。

4 个答案:

答案 0 :(得分: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 :(得分:1)

我同意桑德斯。

您需要外部查询。

除了SELECT DISTINCT(实际上可以归结为SELECT列表的所有列)之外,您不能将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

答案 2 :(得分:0)

我猜想PostgreSQL的DISTINCT ON可以达到目的:

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

这将为您提供userid中每行最少eventdate的行。

答案 3 :(得分: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;

这应该可以解决问题!您可以在外部查询中使用其他聚合函数,并在子查询中使用其他窗口函数。