如何重用 SELECT、WHERE 和 ORDER BY 子句的结果?

问题描述 投票:0回答:3

以下查询返回我们附近的场地(纬度:62.0,经度:25.0),其半径范围内按距离排序:

SELECT *, 
     earth_distance(ll_to_earth(62.0, 25.0), 
     ll_to_earth(lat, lon)) AS distance 
FROM venues 
WHERE earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon)) <= radius 
ORDER BY earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon))

是否可以(并且建议)重新使用

earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon))
的结果,而不是为 SELECT、WHERE 和 ORDER BY 子句单独计算?

sql postgresql select sql-order-by where-clause
3个回答
7
投票

GROUP BY
ORDER BY
子句中,您可以引用列别名(输出列),甚至可以引用
SELECT
列表项的序数。 说明书:

每个表达式可以是 输出列的名称或序号 (SELECT 列表项),或者它可以是由以下形式形成的任意表达式 输入列值。

我的粗体强调。

但是在

WHERE
HAVING
子句中,您只能引用基表中的列(输入列),因此您必须拼写出您的函数调用。

SELECT *, earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon)) AS dist
FROM   venues 
WHERE  earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon)) <= radius 
ORDER  BY distance;

要查看哪个更快,在 CTE 或子查询中计算,只需使用

EXPLAIN ANALYZE
进行测试:

SELECT *
FROM  (
   SELECT *
         ,earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon)) AS dist
   FROM   venues
   ) x
WHERE  distance <= radius 
ORDER  BY distance;

就像Mike评论的那样,通过声明函数

STABLE
(或
IMMUTABLE
),您可以通知查询规划器,函数调用的结果可以在单个语句中针对相同的调用重复使用多次。 说明书:

STABLE
函数不能修改数据库,并且保证 给定 a 中所有行的相同参数,返回相同的结果 单一声明。该类别允许优化器进行优化 对函数的多次调用改为一次调用

我的粗体强调。


3
投票

虽然我主要使用 MS SQL Server,但我非常确定 PostgreSQL 支持 CTE。尝试这样的事情:

WITH CTE_venues AS (
SELECT *, earth_distance(ll_to_earth(62.0, 25.0), ll_to_earth(lat, lon)) AS distance 
FROM venues 
)
SELECT *
FROM CTE_venues 
WHERE distance <= radius 
ORDER BY distance

0
投票

您还可以创建独立或打包函数并在查询中使用它:

 SELECT *
   FROM ...
  WHERE distance <= your_function()  -- OR your_package_name.your_function()
 ORDER BY ...

您可以在选择中使用您的功能:

Select your_function() 
  From your_table...
 Where  ...
© www.soinside.com 2019 - 2024. All rights reserved.