SELECT из представления MySQL с предложением HAVING возвращает пустой набор результатов

У меня и моего делового партнера возникают проблемы с выбором из представления MySQL, в котором есть предложение HAVING.

Запрос просто выбирает несколько полей из представления, динамически определяет расстояние с помощью нескольких вычислений и присваивает ему псевдоним «расстояние», а затем ограничивает результаты теми строками, расстояние между которыми меньше заданной переменной.

Расстояние рассчитывается по формуле Haversine, на которую ссылаются Карты Google: https://developers.google.com/maps/articles/phpsqlsearch

Вот что я знаю:

1) Когда предложение HAVING удаляется из запроса, он успешно возвращает все результаты в представлении, включая вычисленное «расстояние» для каждой строки

2) Когда в запрос добавляется предложение HAVING, он возвращает пустой набор результатов.

3) Мы также попытались заменить переменную в предложении HAVING на статическое число — это также вернуло пустой набор результатов.

Содержимое представления кажется неуместным, так как все работает без предложения HAVING.

Вот запрос:

SELECT 
restaurantName, 
restaurantID, 
locationID, 
locationCity, 
locationState, 
locationAddress, 
locationLatitude, 
locationLongitude,
( 3959 * acos( cos( radians('%s') ) * cos( radians( locationLatitude ) ) * cos( radians( locationLongitude ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( locationLatitude ) ) ) ) AS distance 
FROM newView 
HAVING distance < '%s' 
ORDER BY distance

Помните, что представление идеально вычисляет «расстояние» для каждой выбранной строки без предложения HAVING, поэтому мы убеждены, что проблема кроется в нем... когда мы убираем его, все работает, но возвращается каждая строка в представлении.

Есть идеи, почему предложение HAVING возвращает пустой набор? Является ли предложение HAVING несовместимым с представлениями?


person David Denton    schedule 16.03.2012    source источник


Ответы (2)


Попробуй это:

select * from (
    SELECT 
    restaurantName, 
    restaurantID, 
    locationID, 
    locationCity, 
    locationState, 
    locationAddress, 
    locationLatitude, 
    locationLongitude,
    ( 3959 * acos( cos( radians('%s') ) * cos( radians( locationLatitude ) ) * cos( radians( locationLongitude ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( locationLatitude ) ) ) ) AS distance 
    FROM newView
) S
where distance < '%s' 
ORDER BY distance
person Mosty Mostacho    schedule 16.03.2012
comment
Спасибо за Ваш ответ. Я использовал эту идею здесь (производная таблица) с предложением HAVING вместо предложения where, и теперь оно работает отлично. Большое спасибо. - person David Denton; 16.03.2012

Предложение HAVING предназначено для использования в агрегированных данных, когда вы группируете строки вместе с помощью предложения GROUP BY. Поскольку вы работаете с каждой строкой отдельно, вы должны заменить HAVING предложением WHERE. Дополнительные сведения см. в этом примере.

Использование HAVING для неагрегированных столбцов в вашем списке SELECT является нестандартным поведением, которое поддерживает MySQL, но на которое не следует полагаться. Даже справочник по MySQL не рекомендует это делать:

Не используйте HAVING для элементов, которые должны быть в предложении WHERE. Например, не пишите следующее:

SELECT col_name FROM tbl_name HAVING col_name > 0;

Вместо этого напишите это:

SELECT col_name FROM tbl_name WHERE col_name > 0;

В стороне: если вы передаете аргументы от пользователя в свой запрос (с %s), убедитесь, что вы просматриваете подготовленные операторы. В противном случае у вас может быть явный недостаток безопасности на ваших руках.

person AerandiR    schedule 16.03.2012
comment
Спасибо за ответ, но это не правильно. Предложение HAVING также можно использовать с агрегатными функциями, которые не сгруппированы, что у нас есть в нашем примере — «расстояние». Когда мы не использовали представление, у нас был точно такой же запрос, и он работал, как задумано, за исключением того факта, что нам нужно было представление для упрощения запроса. Ознакомьтесь с документацией Google, на которую я ссылался в вопросе, и вы увидите, как они используют предложение HAVING для ограничения «расстояния», которое является вычисляемым полем. - person David Denton; 16.03.2012
comment
Я попытался заменить HAVING на WHERE, и вместо получения пустого набора результатов я получил ошибку MySQL. Вот запрос Google из документации выше: SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20; - person David Denton; 16.03.2012
comment
Использование HAVING таким образом является нестандартным поведением, которое поддерживает MySQL, но поведение, на которое я бы не стал полагаться. Не используйте HAVING для элементов, которые должны быть в предложении WHERE. Например, не пишите следующее: SELECT col_name FROM tbl_name HAVING col_name > 0; Напишите вместо этого: SELECT col_name FROM tbl_name WHERE col_name > 0; (source) Также обратите внимание, что в вашем примере нет агрегатных функций. Все тригонометрические функции, используемые для вычисления расстояния, работают со столбцами одной строки. - person AerandiR; 16.03.2012
comment
Еще раз спасибо за ваш вклад. Как бы вы порекомендовали структурировать запрос? Поскольку рассчитанное значение «расстояние» отсутствует в представлении, использование предложения WHERE вместо HAVING вызывает ошибку MySQL. - person David Denton; 16.03.2012
comment
Пожалуйста, вы можете поблагодарить меня, проголосовав за мой ответ. :) Взгляните на это решение вашей проблемы. Кроме того, если вы передаете аргументы от пользователя в свой запрос (с %s), обязательно просмотрите подготовленные операторы. В противном случае у вас может быть явный недостаток безопасности на ваших руках. - person AerandiR; 16.03.2012