【问题标题】:PostgreSQL: Selecting N result in group by queryPostgreSQL:按查询选择 N 个结果分组
【发布时间】:2010-01-02 11:09:22
【问题描述】:

我有以下 SQL 查询,可以从我的表中选择一些结果:

select  avg(c3), count(c3), std  
from ssims where obraz = 'lena' group by std order by std

但是我对不同的标准值执行了不同数量的测试,所以它返回给我类似的东西:

0.906176136363636;44;5
0.881669302325582;43;10
0.855873409090909;44;15
0.829195813953488;43;20
0.802071590909091;44;25
0.774523720930233;43;30
0.747213636363636;44;35
0.720115581395349;43;40
0.694712954545455;44;45
0.668683255813953;43;50

我想做的是为每个 std 值选择恒定(即 20)个结果的平均值。所以在这样的查询之后,每行的第二列将是 20。

怎么做?我尝试了limits和top,但没有成功

【问题讨论】:

  • 它应该为每个标准值选择 20 行(不管是哪一行)
  • 如果您只是查看一个随机子集并进行平均,那么如果您执行 20 行或更多行,这有什么关系呢?我可以看到,如果行数太少,会产生不正确的数字,但太多​​了?
  • 不是“太少”或“太多”的情况。我需要为每种情况提供完全相同的数字。在所有比较情况下都有相同的情况,这只是科学测试的一种良好做法。

标签: sql postgresql


【解决方案1】:

PostgreSQL 8.3:

SELECT  a[1] AS avg_std, a[2] AS cnt_std, std
FROM    (
        SELECT  (
                SELECT  ARRAY[AVG(c3) , COUNT(*)]
                FROM    (
                        SELECT  c3
                        FROM    ssims si
                        WHERE   obraz = 'lena'
                                AND si.std = so.std
                        ORDER BY
                                id
                        LIMIT 20
                        ) q
                ) a
        FROM    (
                SELECT  DISTINCT std
                FROM    ssims
                WHERE   obraz = 'lena'
                ) so
        ) q

这将在每个标准的单个索引扫描中同时计算 AVGCOUNT

(obraz, std, id) 上创建一个复合索引以使其快速工作。

PostgreSQL 8.4:

SELECT  AVG(c3), COUNT(*), std
FROM    (
        SELECT  std, c3, ROW_NUMBER() OVER (PARTITION BY std ORDER BY id) AS rn
        FROM    ssims
        WHERE   obraz = 'lena'
        ) q
WHERE   rn <= 20
GROUP BY
        std

【讨论】:

  • 8.4 版本 非常漂亮!谢谢!
【解决方案2】:

假设您的 ssims 表有一个唯一的 id 列,在我的示例中我称之为 id,您可以执行以下操作:

select avg(c3), count(c3), std from ssims where id in 
   (select id from ssims where obraz = 'lena' LIMIT 20)
   group by std order by std;

【讨论】:

  • 是的,它有这样的列,但这不起作用。有一个错误,因为在 gouping 时还必须在子查询中选择 std。错误消息:错误:列“ssims.id”必须出现在 GROUP BY 子句中或在聚合函数中使用
  • 您可以像我现在所做的那样从内部选择中删除 group by 语句并应用于外部选择。根据您需要的结果,您也可以在内部选择中将 id 添加到 group by 语句中。
  • 不,它只会选择 20 个元素,而不是每个 std 值的 20 个元素
  • 啊,是的,我误解了你的问题。
【解决方案3】:

如果您使用的是 8.4,您应该可以使用窗口函数来执行此操作。 (不确定 std 部分是什么,但我相信您可以将其添加回来)像这样的东西(未经测试,因此您可能需要调整一些东西):

SELECT std,avg(c3), count(c3)
FROM (
 SELECT std, c3, row_number() OVER (
  PARTITION BY std ORDER BY random())
 ) foo
WHERE row_number <= 20
GROUP BY std
ORDER BY std

如果你不关心你实际上得到一个随机子集,你可以删除 ORDER BY random() 部分,它会给你一个“几乎随机”的部分。

【讨论】:

  • 呃,我现在看到查询缺少“FROM ssims”。它需要在 ") foo" 部分之前。这就是我所说的“你可能需要调整一些东西”的意思
猜你喜欢
  • 2012-07-13
  • 2021-01-06
  • 1970-01-01
  • 2023-01-20
  • 2012-07-12
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
相关资源
最近更新 更多