在链式查询中保持行排序

时间:2016-11-07 23:29:55

标签: postgresql

这有点浓缩,以使其更容易理解,但我希望这里有要点。我真的很想了解postgresql如何处理行集。

我有一个包含大量项目的'thing'表 - 每个都有很多属性。我有另一个名为'category'表的表。类别是用户定义的,由名称和一些过滤器组成:用户可以建立新类别,然后为其定义属性过滤器。过滤器(存储在“过滤器”表中)确定来自事物表的哪些项目将包含在每个类别中。因此,每个过滤器都标识一个属性类型和一个属性值(或者在某些情况下标识一系列值,但这里并不重要)。

过滤器 与类别关联关联(即每个过滤器都有一个类别ID),但两者都没有与事物表关联关联。相反,我有一个函数,我可以传递一个过滤器行和一个事物行,它将返回该事物中的属性是否被认为与过滤器中的模型属性匹配。

在许多情况下,多个类别将匹配给定的事物。但我只希望它出现在一个类别的输出中。因此,每个类别都有一个匹配优先级字段。此外,生成的行集用于组织显示,因此存在确定“显示”优先级的第二类别属性。 (我还没有真正完成这部分。)

基本上我想要做的是(a)运行一个查询,确定每个事物匹配的类别。然后,我想(b)选择每个事物匹配的第一个类别(最低匹配优先级),然后删除其余部分。最后,我想(c)重新排序结果集,使它们处于显示优先级顺序。

(a)部分似乎工作正常。我的查询如下:

SELECT t.foo, t.bar, <other fields> FROM (category c JOIN filter f USING (category_id))
               JOIN thing t ON fmatch(f, t)
               ORDER BY c.priority);

(fmatch是实现实际匹配算法的函数,似乎工作正常)。

我得到一个结果集,它根据过滤器正确地将每个事物与它应该匹配的每个类别相关联。

下一步是淘汰多场比赛。结果行在上一步结束时的顺序正确,所以我试图只使用“DISTINCT ON(t.foo,t.bar)”字段(事物中没有一个字段保证是唯一的,但是一组复合字段是。)。

WITH results1 AS (<above query>)
SELECT DISTINCT ON (foo, bar) * FROM results1;

但是,此步骤似乎不保持第一个查询的顺序。或者在任何情况下,虽然DISTINCT ON只保留上一步中的一行,但它并不总是保留前一行中的第一行(有时它确实存在,有时不会)。

所以很明显我误解了postgresql如何处理结果集。我假设当我在步骤2中执行“DISTINCT-ON”部分时,步骤1中的排序仍然存在,但似乎并非如此。有人可以解释为什么这不起作用?或者给我一个暗示我如何强迫它维持?或者另一种实现方式?

(我尝试在同一个查询中添加“ORDER BY”和“DISTINCT ON”,但它要求他们使用相同的字段,这在我的情况下是没有意义的。)

如果重要,请使用最新的9.6 postgresql。

1 个答案:

答案 0 :(得分:0)

为后代撰稿......

我找到了一种方法来完成我需要的窗口功能 - 至少看起来它可靠地工作。据我所知,我的解释是:

第一个SELECT将第一个结果集划分为&#34; windows&#34;基于唯一的东西属性,在窗口内按类别优先级对它们进行排序,然后外部的DISTINCT ON选择每个窗口中的第一行。之后,第二个SELECT只按显示顺序对结果行进行排序。

生成的查询如下所示:

WITH res AS (
        SELECT DISTINCT ON (foo, bar)
             c.priority, c.display, t.*,
             row_number() OVER (PARTITION BY (foo, bar) ORDER BY priority)
        FROM (category c JOIN filter f USING (category_id))
             JOIN thing t ON fmatch(f, t))
SELECT * FROM res ORDER BY display;
相关问题