postgresql 所选列必须出现在GROUP BY子句中错误

rbl8hiat  于 2023-10-18  发布在  PostgreSQL
关注(0)|答案(2)|浏览(148)

我正在尝试编写一个SQL查询,以获取特定工具的月底价格。
表(包含一些可以忽略的其他列):
| instrumentId| unitPrice|联系我们|
| --|--|--|
| 1 |九十点二二|2018-10-28 2018-10-28|
| 1 |八十点五五|2018-10-30 2018-10-30|
| 1 |70.55| 2018-09-15 2018-09-15 2018-09-15|
| 1 |七十点五六|2018-09-23 2018-09-23|
预期结果:
| instrumentId| unitPrice|联系我们|
| --|--|--|
| 1 |八十点五五|2018-10-30 2018-10-30|
| 1 |七十点五六|2018-09-23 2018-09-23|
对于同一个instrumentId,将有多个行,其中不同月份的reportedAt不同。这个想法是针对每个月和每年(例如,2018年10月),我试图只得到每个月的最后价格reportedAt

SELECT 
    "instrumentId",
    "unitPrice",
    MAX("reportedAt") as reportedAt
FROM 
    "InstrumentPrice"
WHERE 
    "instrumentId" = 90
GROUP BY 
    EXTRACT(MONTH FROM "reportedAt"),
    EXTRACT(YEAR FROM "reportedAt")
ORDER BY 
    "reportedAt" DESC

但是,这个查询不断抛出一个错误,指出选定的列必须出现在GROUP BY子句中或在聚合函数中使用。
这将不起作用,因为如果我按unitPricereportedAt分组,我将不会得到所需的结果(因为它们都是唯一的)。

8zzbczxx

8zzbczxx1#

查询中的错误是由于将列unitPriceinstrumentId包含在SELECT子句中,而没有将其包含在聚合函数或GROUP BY子句中。
在SQL中,当你使用GROUP BY时,你应该:

  • 在GROUP BY子句中包含该列。
  • 在SELECT子句中对列使用聚合函数(如MAX、MIN、SUM等)。

您可以使用窗口函数来实现这一点。您可以使用ROW_NUMBER()窗口函数,根据reportedAt列为每个月和年分区中的每一行分配一个行号,然后筛选行号为1(表示每个月报告的最后价格)的行。你可以这样做:

SELECT
    "instrumentId",
    "unitPrice",
    "reportedAt"
FROM (
    SELECT
        "instrumentId",
        "unitPrice",
        "reportedAt",
        ROW_NUMBER() OVER (PARTITION BY "instrumentId", EXTRACT(MONTH FROM "reportedAt"), EXTRACT(YEAR FROM "reportedAt") ORDER BY "reportedAt" DESC) AS row_num
    FROM
        "InstrumentPrice"
    WHERE
        "instrumentId" = 90
) subquery
WHERE
    row_num = 1
ORDER BY
    "reportedAt" DESC;

在此查询中:
1.内部子查询使用ROW_NUMBER()窗口函数为每个月和年分区中的每一行分配一个行号。PARTITION BY子句按instrumentId、月和年对数据进行分区,并按reportedAt降序排列每个分区中的行。
1.然后,外部查询选择行号为1的行,这对应于每个月和年组合报告的最后一个价格。

dauxcl2d

dauxcl2d2#

group by不适合您的工作。这里使用窗口函数row_number()

with t as
(
 select 
   instrumentId, unitPrice, reportedAt,
   row_number() over (
                      partition by date_trunc('month', reportedAt)
                      order by reportedAt desc
                     ) as rn
 from the_table
)
select instrumentId, unitPrice, reportedAt
from t where rn = 1;

Demo

相关问题