限制按组设置的结果

时间:2016-02-09 08:45:38

标签: sql postgresql

我有几个表最简单的表格为1:N;例如:

CREATE TABLE X (id INTEGER, foo VARCHAR(16));
CREATE TABLE Y (id INTEGER, x_id INTEGER, bar VARCHAR(16));

和里面的一些数据,如:

INSERT INTO X VALUES (1, 'a'), (2, 'b'), (3, 'c');
INSERT INTO Y VALUES
    (1, 1, 'blue'), (2, 1, 'green'), (3, 1, 'red'),
    (4, 2, 'big'), (5, 2, 'small'),
    (6, 3, 'car'), (7, 3, 'bike'), (8, 3, 'skate');

我想做什么:从两个表中选择实体,限制x.id。例如,我需要选择2个实体,然后这将无法正常工作:

SELECT x.id, x.foo, y.id, y.bar
FROM x INNER JOIN y ON x.id = y.x_id
LIMIT 2

因为if会对最终生成的行集应用限制,而不是基于x.id。结果应该是:

x.id x.foo y.id y.bar
 1    'a'   1  'blue'
 1    'a'   2  'green'
 1    'a'   3  'red'
 2    'b'   4  'big'
 2    'b'   5  'small'

我的想法是编写一些块分子,它将添加" block"数字到结果行集,然后代替LIMIT使用WHERE,所以:

SELECT block_number, x.id, x.foo, y.id, y.bar
FROM x INNER JOIN y ON x.id = y.x_id
WHERE block_number <= 2

但到目前为止,我没有找到任何获得该区号的好方法。 &#34;良好的&#34;的意思是:

  • 没有子查询。原始选择可能非常复杂并涉及许多表,但它很快,因为连接都是通过索引字段。而且我不想打破表现
  • 理想情况下,没有新的join-s。自Postgres支持
  • 以来,一些窗口函数可能是一个很好的解决方案

我尝试过这样的事情:

SELECT row_number() OVER (PARTITION BY x.id), x.id, x.foo, y.id, y.bar
FROM x INNER JOIN y ON x.id = y.x_id
WHERE block_number <= 2

但是,遗憾的是,这会在块中提供行号,而不是块,因此不能用于我的问题。

此外,选择x记录并限制它&#34;事先&#34;在这样的子查询中:

SELECT x.id, x.foo, y.id, y.bar
FROM 
  (SELECT x.id LIMIT 2) AS x
    INNER JOIN y ON x.id = y.x_id

不是一种选择。这是因为:

  • 原始查询包含所有表格中的字段,我不确定哪个表格属于哪个表格。我可以添加一些机制来确定它,但它会减慢应用程序的速度。初始查询是动态生成的
  • 更多,原始查询可能包含ORDER BY子句,因为我无法为仅针对表ORDER BY的子查询编写正确的x

所以,重要添加:解决方案应该尊重原始查询顺序。最简单的说明方式是:

SELECT block_number, x.id, x.foo, y.id, y.bar
FROM x INNER JOIN y ON x.id = y.x_id
WHERE block_number <= 2
ORDER BY x.id DESC

应该产生:

block_number x.id x.foo y.id y.bar
     1        3    'c'   6  'car'
     1        3    'c'   7  'bike'
     1        3    'c'   8  'skate'
     2        2    'b'   4  'big'
     2        2    'b'   5  'small'

即。应该正确计算块以保持原始订单。而且,我无法预测初始订单,因为它是动态指定的。

P.S。

抱歉,因为没有提供sql小提琴。该资源不适合我,而且已经很长时间了。

另外,我的Postgres版本是:9.4,所以任何&#34; new&#34;可以实现我的目标的功能 - 可以应用。

1 个答案:

答案 0 :(得分:3)

您可以使用窗口函数dense_rank()。 无法在WHERE子句中调用窗口函数,因此必须将其放在子查询中:

<div class="collapse navbar-collapse" id="navbar-brand-centered">