这是我之前发布的稍微更难的版本。我不想编辑原文来破坏我当时的问题的完美答案。
假设一个名为tau的表。
tau:
A | B | C
----------
2 - 1 - red
3 - 1 - rod
4 - 1 - rope
6 - 5 - red
7 - 5 - rap
8 - 5 - rod
9 - 10 -rod
11- 10 -road
12- 13 -rud
A列是主键。它将是独一无二的。 B列是外键。在我的数据库中,没有整数键在表之间是相同的。 C列不是关键。
这个表会有很多行。还有许多其他列,例如列C,它们是为搜索索引的。
我想从B列得到M个不同的值。让我们说M = 2
重要的是,我在表达式中使用了B列(它也被编入索引!)以确定要返回的B。
通常,我会去
select distinct B From tau Where C like 'r_d' AND B < 13 Order By B Desc Limit 2
我得到了
B
-----
10
5
这是现在的现状。但我想升级到一个新场景:
当满足BC上的表达式并将记录添加到结果堆中时(C类似于&#39; r_d&#39; AND B&lt; 13),我想要返回列A和列B,同时保持2个最多不同B列值的限制。
另一个重要条件是解决方案必须适用于where子句中的表达式,该表达式对于可能不同的C值返回true。
看哪,我想要的结果。
A | B
------
9 - 10
8 - 5
6 - 5
问题是,返回的记录的实际限制可能大于M,或者示例中为2。我不太关心有多少记录通过,只要只有M个不同的B值。如何在Postgresql中编写查询来完成此操作?
答案 0 :(得分:3)
DENSE_RANK
应该做你需要的。这是SQL Fiddle。
将您的M
放入WHERE R.rnk <= 2
而不是2
。
我不是从M
的{{1}}个不同的值开始,而是试图找出如何将B
列中的缺失值添加到最终结果中,而是考虑到这一点来自另一方的问题。我们有一些搜索条件将整个表限制为一些中间结果集:
A
此中间结果集包含表中的所有列,但尚未汇总任何内容。我们只需要进一步过滤此集合,只保留SELECT *
FROM tau
WHERE C LIKE 'r_d' AND B < 13
列的M
个不同值。 B
为每组DENSE_RANK
值分配一个数字(无间隙),因此我们可以在最终过滤器中使用它。
B
结果集
SELECT
A, B
FROM
(
SELECT
A
,B
,C
,DENSE_RANK() OVER(ORDER BY B DESC) AS rnk
FROM tau
WHERE C LIKE 'r_d' AND B < 13
) AS R
WHERE R.rnk <= 2
ORDER BY B DESC, A DESC;
使用LATERAL JOIN的第二个变体
SQL Fiddle包含两种变体。
在第二个版本中,我们首先发现A B
9 10
8 5
6 5
M
的不同值。然后,对于每个找到的值,我们使用针对此B
值的额外过滤器运行主查询。如果B
有数百万个不同的值,那么只要B
上有索引,过滤到特定值应该是有效的。如果有数百万行,但B
的总不同值的数量很小,则应该很慢。
B