我有我想能够呈现出表“中名列Y中取X的”数据。 具体地讲,我想能够呈现数据为单个行中的相对有效的方式(即,没有在表中选择的每一行)。 排名本身很简单,它是一个直ORDER BY对表中的一列。
Postgres的似乎目前在这方面的一些独特的挑战; AFAICT它没有一个RANK或ROW_NUMBER或同等功能(至少在8.3,其中我卡上的时刻)。 在邮件列表归档的规范答案似乎是创建一个临时序列,并从中选择:
test=> create temporary sequence tmp_seq;
CREATE SEQUENCE
test=*> select nextval('tmp_seq') as row_number, col1, col2 from foo;
这样看来,解决方案仍然无助的时候我想从表中选择一个单行(我想通过PK来选择它,而不是按排名)。
我可以非规范化和等级存储在一个单独的列,这使得呈现的数据琐碎的,但只是我重新定位的问题。 更新不支持ORDER BY,所以我不知道我怎么会构建一个更新查询设置行列(短期选择每行每运行一个单独的更新每一行,这似乎是太多的DB活动的触发每次行列需要更新)。
我失去了一些东西明显? 什么是正确的方式做到这一点?
编辑 :显然,我不太清楚。 我知道OFFSET /限制的,但我看不出它如何帮助解决这个问题。 我并不想选择第十届排名第一的项目,我想选择任意的项目(通过其PK,说的),然后就可以显示给用户的东西,如“排名第43位出312”
如果你想排名,这样做
SELECT id,num,rank FROM (
SELECT id,num,rank() OVER (ORDER BY num) FROM foo
) AS bar WHERE id=4
或者,如果你真的想行号,使用
SELECT id,num,row_number FROM (
SELECT id,num,row_number() OVER (ORDER BY num) FROM foo
) AS bar WHERE id=4
当你有相同价值观的地方,他们会有所不同。 还有DENSE_RANK()如果你需要的。
这当然需要的PostgreSQL的8.4。
是不是只是这样的:
SELECT *
FROM mytable
ORDER BY
col1
OFFSET X LIMIT 1
或者我失去了一些东西?
更新:
如果你想显示的级别,使用:
SELECT mi.*, values[1] AS rank, values[2] AS total
FROM (
SELECT (
SELECT ARRAY[SUM(((mi.col1, mi.ctid) < (mo.col1, mo.ctid))::INTEGER), COUNT(*)]
FROM mytable mi
) AS values
FROM mytable mo
WHERE mo.id = @myid
) q
ROW_NUMBER
在PostgreSQL的功能是通过实施LIMIT n OFFSET skip
。
编辑:既然你问了ROW_NUMBER()
而不是简单的排名: row_number()
被引入到PostgreSQL 8.4版本。 所以,你可能会考虑更新。 否则, 这种解决方法可能会有所帮助。
上一页答复解决的问题是“选择所有的行,并得到他们的排名”,这是不是你想要的?
做就是了 :
SELECT COUNT(*)FROM表WHERE分数> $ 1
其中$ 1是你刚才选择的行的评分(我想你想显示它,所以你可能会选择它...)。
或做:
选择一个。 ,(SELECT COUNT()FROM表B其中得分> b.score)AS秩FROM表作为其中pk = ...
但是,如果您选择的是排名最后一排,是的,你需要计算其前都排在所有行,所以您需要扫描整个表,这将是非常缓慢的。
解决方案:
SELECT COUNT(*)FROM(SELECT 1 FROM表WHERE分数> $ 1 LIMIT 30)
你会得到精确的排名为30个成绩最好,这将是快。 谁在乎失败者?
OK,如果你真的对失败者照顾,你需要做一个直方图:
假设分数可以去从0到100,你有百万失败者评分<80和10名获奖者与得分> 80。
你使多少行有一个分数X的直方图,这是一个简单的小桌子与100行。 触发器添加到您的主表更新直方图。
现在,如果你想排名具有分值x一个失败者,他的军衔是sum(HISTO)其中histo_score> X.
由于你的分数可能不是介于0十亿0和100之间,而(说),并且你需要掰过来了一下,扩大你的直方图区间,例如。 所以你只需要100个箱最大,或者使用一些日志直方图分布函数。
顺便说Postgres的确这样当你分析表中,因此,如果您设置statistics_target到100或1000的成绩,分析,然后运行:
EXPLAIN SELECT * FROM表WHERE分数> $ 1
你会得到一个不错的行数的估计。
谁需要确切的答案?