【问题标题】:PostgreSQL ORDER BY with VIEWs带有视图的 PostgreSQL ORDER BY
【发布时间】:2013-01-16 05:03:23
【问题描述】:

假设我想编写一个使用VIEW 的简单SELECT 查询:

CREATE TEMP VIEW people AS
SELECT 
     p.person_id
    ,p.full_name
    ,p.phone
FROM person p
ORDER BY p.last_name;

SELECT
     p.*
    ,h.address
    ,h.appraisal
FROM people p
LEFT JOIN homes h
     ON h.person_id = p.person_id
ORDER BY p.last_name, h.appraisal;

这里明显的问题是,当我去执行最终的ORDER BY 时,p.last_name 不再可用。

如何对最终查询进行排序,以便 people 视图的原始序列跟随最终查询?

这里的简单解决方案是在视图中包含 p.last_name。我不想那样做——我在现实世界中的例子(要复杂得多)让这成为一个问题。

过去我对临时表做过类似的事情。例如,我使用CREATE TEMP TABLE testing WITH OIDS 创建表,然后执行ORDER BY testing.oid 以通过原始序列。

是否可以对视图做同样的事情?

【问题讨论】:

  • last_namepeople 视图中有什么问题?
  • 我的实际视图和查询比我上面给出的简化粒度示例要复杂得多。解释为什么我想避免通过额外的列是不必要的复杂。要回答这个问题,您必须在不了解原因的情况下接受该要求。
  • 我总是对 Postgres 允许在视图中使用 order by 感到惊讶。这根本没有意义。
  • 哈哈。可能有点草率或只是养眼。就关系而言,无论如何它都没有意义:结果集是无序的,因此可以忽略任何排序。它不会造成伤害(就像 exists(...) 相关子查询中的 LIMIT 1 ...)顺便说一句:在这种情况下,它确实有意义:在外部查询中使用 VIEW 或在子查询中。子查询可能会忽略;外部查询可能不会。
  • 我冒昧地修复了问题中视图创建的非法语法,因为它不会干扰问题。

标签: sql postgresql sql-order-by sql-view postgresql-9.2


【解决方案1】:

idea of @sgeddes 为基础,但改用rank()

SELECT p.*
      ,h.address
      ,h.appraisal
FROM  (SELECT *, rank() OVER() AS rn FROM people) p
LEFT  JOIN homes h ON h.person_id = p.person_id
ORDER BY p.rn, h.appraisal;

我提供了一个测试用例来演示差异。
->sqlfiddle

【讨论】:

    【解决方案2】:

    如果您使用row_number() over(),这是可能的。

    这是一个例子:

    SELECT
        p.*
        ,h.address
        ,h.appraisal
    FROM (SELECT *, row_number() over() rn FROM people) p
    LEFT JOIN homes h
        ON h.person_id = p.person_id
    ORDER BY p.rn, h.appraisal;
    

    这是您可以用来测试的SQL Fiddle

    正如@Erwin Brandstetter 正确指出的那样,使用rank() 将产生正确的结果并允许对其他字段进行排序(在本例中为评估)。

    SELECT
        p.*
        ,h.address
        ,h.appraisal
    FROM (SELECT *, rank() over() rn FROM people) p
    LEFT JOIN homes h
        ON h.person_id = p.person_id
    ORDER BY p.rn, h.appraisal;
    

    这样想,使用 row_number(),它总是只按该字段排序,而不管任何其他排序参数。通过使用相同关系的 rank(),可以轻松搜索其他字段。

    祝你好运。

    【讨论】:

    • @ElliotB.:实际上,这个答案几乎是正确的,但并不完全正确。如果lastname 在表person 中有相同的对等点,row_number() 分配一个不同的(实际上是随机的)数字,并且您得到的结果与按原始列 lastname 加上 appraisal 排序时不同。解决方法:改用rank()
    • @ElliotB:只需将上面的 row_number 更改为排名。这样想,row_number 不会对 smith 1000 与 smith 100 进行排序——它只使用原始的 row_number。很好,我会编辑我的回复。
    • @ErwinBrandstetter -- 非常感谢 -- 请参阅上面的编辑!甚至没有考虑对其他参数进行排序。很棒的收获。
    • 除此之外,我喜欢你的想法。 +1。
    【解决方案3】:

    创建一个 row_number 列并在选择中使用它。

    CREATE TEMP VIEW people AS
    SELECT 
         row_number() over(order by p.last_name) as i
        ,p.person_id
        ,p.full_name
        ,p.phone
    FROM person p
    
    SELECT
         p.*
        ,h.address
        ,h.appraisal
    FROM people p
    LEFT JOIN homes h
         ON h.person_id = p.person_id
    ORDER BY p.i, h.appraisal
    

    【讨论】:

    • 无需将 row_number() 添加到视图中。你可以像我在下面那样使用它。无论哪种方式,很好的答案!
    • 这里有同样的问题。应该是rank()
    猜你喜欢
    • 2019-05-31
    • 2012-03-17
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 2012-04-05
    相关资源
    最近更新 更多