2015-02-05 3 views
1

У меня есть предложение SELECT в функции, в которой я соединяю две таблицы, чтобы найти рестораны, которые находятся на определенном расстоянии от пользователя и в настоящее время открытый. По какой-то причине, когда я запускаю эту функцию я получаю следующую ошибку:SELECT AS colName во внутреннем соединении, colName не существует (Postgres)

ERROR: column "distance" does not exist 
LINE 10:    distance < searchDist AND 
        ^

Вот мой код:

CREATE OR REPLACE FUNCTION get_nearby_open_restaurants (searchDist integer, myLat numeric, myLon numeric) 
RETURNS json AS $$ 
BEGIN 
CREATE TEMPORARY TABLE nearbyOpenRestaurants AS 
    SELECT Restaurants.restaurantID, Restaurants.name, Restaurants.type, 
      Restaurants.address, Restaurants.deliveryDistance, 
      (3959 * acos(cos(radians(myLat)) * cos(radians(latitude)) * 
      cos(radians(longitude) - radians(myLon)) + 
      sin(radians(myLat)) * sin(radians(latitude)))) AS distance, 
      BusinessHours.hoursJSON 
    FROM Restaurants, BusinessHours 
    WHERE Restaurants.RestaurantID = BusinessHours.RestaurantID AND 
      distance < searchDist AND 
      distance < Restaurants.deliveryDistance 
    /*Check if the restaurant is open here*/ 
    ; 

RETURN to_json(nearbyOpenRestaurants); 
DROP TABLE nearbyOpenRestaurants; 
END; 
$$ LANGUAGE plpgsql; 

Просто уточнить, ВЫБОР AS пункта, содержащего расчет расстояния работает только штрафом в его стол, например:

SELECT restaurantID, name, type, address, deliveryDistance, 
    (3959 * acos(cos(radians(myLat)) * cos(radians(latitude)) * 
    cos(radians(longitude) - radians(myLon)) + 
    sin(radians(myLat)) * sin(radians(latitude)))) AS distance 
    FROM Restaurants 
    HAVING distance < searchDist AND distance < deliveryDistance; 

Таким образом, проблема возникает только тогда, когда я соединяю две таблицы вместе. Предложение HAVING, похоже, не помогает в объединенном SELECT. Что я делаю неправильно? Благодаря!

ответ

0

Ваша проблема заключается в том, что distance здесь есть псевдоним в SELECT, который пока недоступен в предложении WHERE. В отдельной таблице это еще один столбец.

Таким образом, вместо того, чтобы distance в WHERE, повторите всю операцию:

sin(radians(myLat)) * sin(radians(latitude))))

Так что ваша статья WHERE бы стать:

WHERE Restaurants.RestaurantID = BusinessHours.RestaurantID AND 
      (sin(radians(myLat)) * sin(radians(latitude))))) < searchDist AND 
     (sin(radians(myLat)) * sin(radians(latitude))))) < Restaurants.deliveryDistance 

Я добавил вмещающих скобки для дальнейшего очерчивания и добавить дополнительная ясность.

Редактировать в ответ на комментарий от OP:

Это повторение calcuations просто так, как это должно быть сделано в SQL если вы хотите повторно использовать значение из SELECT в WHERE того же запроса. Как правило, повторный расчет не является большой проблемой (я считаю, что он имеет некоторое кэширование, чтобы помочь с этим), и я подозреваю, что эти вычисления, которые являются прямыми вычислениями в математике, не являются исключением, поэтому я бы рекомендовал пойти с этим повторяющийся метод.

Если вы наткнулись в случае, когда что-то было по-настоящему дорогой запрос, и вы обнаружили, что встроенные в кэшированиях делали повторяя выражение дорогой, есть два варианта:

Один использовать CTE , который включает выражение WITH. Это полезно для независимых запросов, т. Е. Запросов, которые не зависят от ввода запроса, в котором вы его будете использовать. Это в основном функционирует как временная таблица запросов. Однако в вашем случае ваше повторное выражение не является постоянным - оно изменяется в зависимости от конкретной строки из ваших JOIN ed tables - и поэтому CTE не сработает для вас.

Другой обернуть SELECT внутри другого SELECT, передвигая положение WHERE к внешнему SELECT, так что distance столбец доступен вам во внешнем SELECT.Однако при таком подходе вам нужно будет убедиться, что ваш внутренний SELECT вернул все необходимые столбцы, которые внешний SELECT необходимо в своем предложении WHERE, что потребует добавления столбцов в ваш случай, и в целом просто кажется более сложным вопрос, чем он должно быть, хотя сложность, вероятно, была бы уменьшена, если бы использовался новый синтаксис JOIN, где критерии были перемещены за пределами WHERE и JOIN ... ON.

Так что, опять же, я бы рекомендовал повторить выражение. Только попытайтесь оптимизировать, если это абсолютно необходимо.

Редактировать в repsonse на 2-й комментарий от OP:

Он не должен иметь ничего общего с ли или не соединены таблицы - ссылающийся не сглаженный столбец из SELECT не будет работать в HAVING или WHERE в особой таблице.

например.

mydb=# create table bar (id serial, val decimal); 
CREATE TABLE 
mydb=# insert into bar (val) values (1.2), (1.1), (3.2); 
INSERT 0 3 
mydb=# select * from bar; 
id | val 
----+----- 
    1 | 1.2 
    2 | 1.1 
    3 | 3.2 
(3 rows) 

mydb=# select id, val, sin(val) from bar; 
id | val |   sin   
----+-----+--------------------- 
    1 | 1.2 | 0.932039085967226 
    2 | 1.1 | 0.891207360061435 
    3 | 3.2 | -0.0583741434275801 
(3 rows) 

mydb=# select id, val, sin(val) as narf from bar; 
id | val |  narf   
----+-----+--------------------- 
    1 | 1.2 | 0.932039085967226 
    2 | 1.1 | 0.891207360061435 
    3 | 3.2 | -0.0583741434275801 
(3 rows) 

mydb=# select id, val, sin(val) as narf from bar having narf > 0; 
ERROR: column "narf" does not exist 
LINE 1: select id, val, sin(val) as narf from bar having narf > 0; 
                 ^
mydb=# select id, val, sin(val) as narf from bar having sin(val) > 0; 
ERROR: column "bar.id" must appear in the GROUP BY clause or be used in an aggregate function 
LINE 1: select id, val, sin(val) as narf from bar having sin(val) > ... 
      ^

mydb=# select id, val, sin(val) as narf from bar where narf > 0; 
ERROR: column "narf" does not exist 
LINE 1: select id, val, sin(val) as narf from bar where narf > 0; 
                 ^
mydb=# select id, val, sin(val) as narf from bar where sin(val) > 0; 
id | val |  narf   
----+-----+------------------- 
    1 | 1.2 | 0.932039085967226 
    2 | 1.1 | 0.891207360061435 
(2 rows) 
+0

Привет, Я думал об этом, но, похоже, неэффективно делать расчет дважды. Что еще более важно, мне нужен столбец расстояния в таблице результатов, который я возвращаю как json. – Teboto

+0

Нет ничего плохого в том, чтобы наложить его на 'расстояние' в' SELECT' - вы просто не можете использовать его в 'WHERE' - но я бы не стал беспокоиться о производительности с повторными вычислениями в целом, особенно для тех, которые носят более простой характер. Подробнее о редактировании моего ответа. – khampson

+0

Спасибо, я рассмотрю ваши решения. Я просто очень смущен, почему псевдоним 'distance' доступен для использования в' WHERE' или 'HAVING' в выражении' SELECT', в котором я не присоединяюсь к таблицам. Может ли быть, что объединенные «SELECT» и индивидуальные «SELECT» выполняются в разных порядках? Я редактировал свой вопрос, чтобы включить код из отдельного 'SELECT' для уточнения. – Teboto