Sql 如何重用SELECT、WHERE和ORDER BY子句的结果?
以下查询返回我们附近的场地lat:62.0,lon:25.0,其半径按距离排序:Sql 如何重用SELECT、WHERE和ORDER BY子句的结果?,sql,postgresql,select,sql-order-by,where,Sql,Postgresql,Select,Sql Order By,Where,以下查询返回我们附近的场地lat:62.0,lon: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_
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\u distancell\u to\u earth62.0、25.0、ll\u to\u EarthAt、lon的结果,而不是单独计算SELECT、WHERE和ORDER BY子句?虽然我主要使用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
您还可以创建独立函数或打包函数,并在查询中使用它:
SELECT *
FROM ...
WHERE distance <= your_function() -- OR your_package_name.your_function()
ORDER BY ...
在GROUP BY和ORDER BY子句中,可以引用列别名、输出列,甚至是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;
与此类似,通过声明函数稳定或不可变,您可以通知查询计划器,函数调用的结果可以在单个语句中重复使用多次。我引述:
稳定的函数不能修改数据库,并保证
如果给定同一行中所有行的相同参数,则返回相同的结果
单一声明。此类别允许优化器进行优化
将函数的多个调用转换为单个调用
粗体强调我的。我认为如果函数标记为,结果将被重复使用。如果我错了,希望博士后专家能纠正我。@MikeChristensen:是的,这就是它通常的工作原理。即使是稳定的也足够了,因为它在一条语句中声明了result常量。即使在事务之间,也需要使用IMMUTABLE来断言常量结果。这是一个函数在索引中可用所必需的,例如,完全无用的答案。1计算的距离仍需要在select子句中,即select*不起作用。2结果集仍然必须按函数结果排序。3这相当于一个查询,与最初发布的内容完全相同。问题是关于函数的波动性,以及查询优化器是对函数求值三次还是一次。。。请再看一次我的例子-函数可以在选择中使用。。。仅供参考。。。问题是如何重用结果。函数返回一个结果,可以重用…很好的答案。需要明确的是:您怀疑子查询将比CTE快,或者怀疑使用CTE/子查询而不是仅仅计算两次是否值得?@randomguy:我希望普通形式比使用子查询或CTE都快。但只要测试一下就知道了。测试>>猜测。@ErwinBrandstetter:根据我的经验,CTE始终保持不变,即使只引用一次,哪个IMO应该与等效视图或子查询表单等效。因此,它们不会被计划生成器分解和重新组装,这可能导致次优计划。有利的一面是:这将使射程表相对较小,且不相关,这将减少可能计划数量的组合爆炸。我没有试过9.2yet@wildplasser:如果您的观察结果成立,那么CTE对于非常大和复杂的查询的有用性会增加,因为在这些查询中,规划开销开始影响性能。您应该将不会进一步优化的子查询放入CTE中,以降低主查询的复杂性。等我有时间的时候,我得测试一下。
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;
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;