2016-02-02 5 views
0

У меня есть 3 стола.ГДЕ условие на значение подзапроса

table deals 
+----+------+-------------+ 
| id | name | location_id | 
+----+------+-------------+ 

table deals_user_actions 
+---------+---------+ 
| deal_id | user_id | 
+---------+---------+ 

table locations 
+----+-----------+----------+ 
| id | longitude | latitude | 
+----+-----------+----------+ 

Мой исходный рабочий запрос был:

SELECT d.id, d.title 
FROM deals d 
JOIN locations l ON l.id = d.location_id 
WHERE ST_Distance_Spheroid(ST_MAKEPOINT(l.longitude, l.latitude), ST_MAKEPOINT(18, 59), 'SPHEROID[\"WGS 84\",6378137,298.257223563]') < 50 

Но мне нужно выбрать сделки, которые имеют только определенное количество действий пользователя, например:

SELECT 
    d.id, 
    d.title, 
    COUNT(dua.deal_id) AS numUserActions 
FROM deals d 
JOIN locations l ON l.id = d.location_id 
JOIN deals_user_actions dua ON dua.deal_id = d.id 
WHERE 
    ST_Distance_Spheroid(ST_MAKEPOINT(l.longitude, l.latitude), ST_MAKEPOINT(18, 59), 'SPHEROID[\"WGS 84\",6378137,298.257223563]') < 50 
    AND numUserActions == 10 

Но вот он жалуется об отсутствии столбцов d.id, l.longitude и l.litude в предложении GROUP BY. Но когда я добавляю их, в запросе возвращается только один результат.

Итак, как бы вы рекомендовали изменить запрос, чтобы дать результат, обусловленный таблицей COUNTed JOINed?

+0

или вы можете удалить '' d.id' из select' – potashin

ответ

3

Нет причин для присоединения deals_user_actions. Просто используйте подзапрос в вашей ИНЕКЕ сосчитать:

SELECT d.id, d.title 
FROM deals d 
JOIN locations l ON l.id = d.location_id 
WHERE ST_Distance_Spheroid(ST_MAKEPOINT(l.longitude, l.latitude), 
          ST_MAKEPOINT(18, 59), 
          'SPHEROID[\"WGS 84\",6378137,298.257223563]') < 50 
AND (select count(*) from deals_user_actions dua where dua.deal_id = d.id) = 10 

UPDATE 1: Если вы хотите, чтобы показать количество действий, а затем присоединиться агрегированные данные вместо:

SELECT d.id, d.title, dua.actions 
FROM deals d 
JOIN locations l ON l.id = d.location_id 
JOIN 
(
    select deal_id, count(*) as actions 
    from deals_user_actions 
    group by deal_id 
    having actions = 10 
) dua ON dua.deal_id = d.id 
WHERE ST_Distance_Spheroid(ST_MAKEPOINT(l.longitude, l.latitude), 
          ST_MAKEPOINT(18, 59), 
          'SPHEROID[\"WGS 84\",6378137,298.257223563]') < 50 

UPDATE 2 : Для полноты я покажу вам ваш первоначальный запрос, слегка измененный с помощью GROUP BY и HAVING. Вы видите, что при запросе совокупного результата (COUNT(*) здесь) вы не можете сделать это в WHERE, который работает с записями таблиц, но в HAVING, который работает с агрегированными группами.

Однако, хорошая привычка присоединяться к агрегатам, как я показал выше, а не сначала присоединяться к таблицам, а затем объединяться, как показано ниже. (С последним вы легко получить проблемы, когда приходится работать с агрегатами из нескольких таблиц.)

SELECT 
    d.id, 
    d.title, 
    COUNT(dua.deal_id) AS numUserActions 
FROM deals d 
JOIN locations l ON l.id = d.location_id 
JOIN deals_user_actions dua ON dua.deal_id = d.id 
WHERE ST_Distance_Spheroid(ST_MAKEPOINT(l.longitude, l.latitude), 
          ST_MAKEPOINT(18, 59), 
          'SPHEROID[\"WGS 84\",6378137,298.257223563]') < 50 
GROUP BY d.id, d.title 
HAVING numUserActions = 10 
+1

Вот умный! :) Но что, если я хочу вернуть значение в результат? – Doodlemeat

+0

Спасибо за отличный ответ и объяснение. Прекрасно работает! – Doodlemeat

+0

О, одна проблема. В вашем примере UPDATE1 я не могу указать в предложении WHERE, что мне нужны только транзакции с 10 действиями пользователя (WHERE COALESCE (dua.actions, 0) = 10). В нем говорится, что «столбца dua.actions не существует». Я тоже старался использовать поле, но без успеха. – Doodlemeat

Смежные вопросы