“where”中使用的 RANK 返回无效列,但存在于结果集中

roy*_*fal 5 postgresql

我基本上有一张带有date, timestamp, DID,的表coordinates

我想要一个查询,该查询将返回包含第 X 天的最后一个坐标、第 X+1 天的第一个坐标以及坐标的行。所以它只会返回有 2 个连续日期的结果。

这就是我想出的。一直试图让这个查询工作,它几乎是完美的,但我只需要添加注释掉的where条件,它就会完全符合我的要求。但是当我取消注释时,我收到一个错误“列不存在”:

SELECT  a.timestamp_intersecting_date d1,b.timestamp_intersecting_date d2,   
        a."DID", 
        a.timestamp_intersecting_max t1, b.timestamp_intersecting_min t2,
        RANK () OVER ( 
          PARTITION BY a.timestamp_intersecting_date
          ORDER BY a.timestamp_intersecting_max DESC
       ) timestamp_d1_rank ,
        RANK () OVER ( 
          PARTITION BY b.timestamp_intersecting_date
          ORDER BY b.timestamp_intersecting_max ASC
       ) timestamp_d2_rank,
        a.coords_centroid, b.coords_centroid
FROM
    signals a
INNER JOIN signals b ON (a."DID" = b."DID")
WHERE (b.timestamp_intersecting_date = a.timestamp_intersecting_date + INTERVAL '1 DAY')
AND a."DID" = b."DID"
--AND timestamp_d1_rank = 1
--AND timestamp_d2_rank = 1
ORDER BY a."DID", t1 desc, t2 asc
Run Code Online (Sandbox Code Playgroud)

如何解决这个问题?

Vér*_*ace 5

不能在WHERE子句中使用别名,也不能使用窗口函数。

\n\n

为了进行演示,请考虑这个示例(fiddle)。

\n\n
CREATE TABLE payment (amount INTEGER, pay_date DATE);\n\nINSERT INTO payment VALUES (54,  \'2019-09-01\'), (56,  \'2019-09-01\'), (154, \'2019-09-02\'), \n(156, \'2019-09-02\'), (254, \'2019-09-03\'), (256, \'2019-09-03\');\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后运行以下两个查询:

\n\n
SELECT \n  *, \n  SUM(amount) OVER (PARTITION BY pay_date) AS the_sums\nFROM payment\nWHERE the_sums > 200; -- ERROR:  column "the_sums" does not exist\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
SELECT \n  *, \n  SUM(amount) OVER (PARTITION BY pay_date) AS the_sums\nFROM payment\nWHERE SUM(amount) OVER (PARTITION BY pay_date) > 200;\n-- ERROR:  window functions are not allowed in WHERE\n
Run Code Online (Sandbox Code Playgroud)\n\n

您没有发布错误消息或 PostgreSQL 版本,但您的问题是 和timestamp_d1_ranktimestamp_d2_rank别名。

\n\n

您有两个选择:

\n\n
    \n
  • 第一个选项:在子查询中使用别名/窗口函数(也在小提琴中)
  • \n
\n\n


\n\n
SELECT * FROM\n(\nSELECT \n  *, \n  SUM(amount) OVER (PARTITION BY pay_date) AS the_sums\nFROM payment\n) AS tab\nWHERE the_sums < 200;\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n
amount    pay_date  the_sums\n    54  2019-09-01       110\n    56  2019-09-01       110\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 第二个选项:您可以使用CTE(又名此处WITH概述的子句或@ypercube\xe1\xb5\x80\xe1\xb4\xb9 \'s 上面的答案,或者也参见小提琴。
  • \n
\n\n

有关整个区域的详细解释,请参见此处

\n


ype*_*eᵀᴹ 4

您不能在子句中使用窗口/排名函数或其别名,WHERE因为它们在 , 中进行评估SELECT,然后再WHERE进行 评估。

WHERE在评估窗口函数后,您可以使用子查询(派生表或 CTE)来处理第二个子句:

SELECT d1, d2,
       "DID",
       t1, t2,
       coords_centroid_a,
       coords_centroid_b
FROM
  (
    SELECT  a.timestamp_intersecting_date d1, b.timestamp_intersecting_date d2,   
            a."DID", 
            a.timestamp_intersecting_max t1, b.timestamp_intersecting_min t2,
            RANK () OVER ( 
              PARTITION BY a.timestamp_intersecting_date
              ORDER BY a.timestamp_intersecting_max DESC
           ) timestamp_d1_rank ,
            RANK () OVER ( 
              PARTITION BY b.timestamp_intersecting_date
              ORDER BY b.timestamp_intersecting_max ASC
           ) timestamp_d2_rank,
            a.coords_centroid AS coords_centroid_a, 
            b.coords_centroid AS coords_centroid_b
    FROM
        signals a
    INNER JOIN signals b ON (a."DID" = b."DID")
    WHERE (b.timestamp_intersecting_date = a.timestamp_intersecting_date + INTERVAL '1 DAY')
    AND a."DID" = b."DID"
  ) AS t
WHERE t.timestamp_d1_rank = 1
  AND t.timestamp_d2_rank = 1
ORDER BY "DID", t1 DESC, t2 ASC ;
Run Code Online (Sandbox Code Playgroud)