2014-09-11 2 views
0

У меня есть два основных оператора SELECT, которые возвращают желаемые результаты при выполнении отдельно, но при объединении не возвращают желаемый результат.Проблема MySQL с комбинированными операторами SELECT

Запрос 1

Это прекрасно работает, возвращая ожидаемый результат.

SELECT feed_mode_id FROM user WHERE id=2; 
+--------------+ 
| feed_mode_id | 
+--------------+ 
|   1 | 
+--------------+ 

Запрос 2

Это также хорошо. Иногда результат будет пустым, иногда нет.

SELECT 
     answer.id AS answer_id 
    FROM 
     answer 
    WHERE 
     answer.question_id = (
      SELECT 
       question.id 
      FROM 
       question 
      ORDER BY 
       datetime_added_utc DESC 
      LIMIT 1 
     ) 
     AND answer.user_id = 2; 

Empty set (0.00 sec) 

Запрос 1 и 2 в сочетании

При объединении их в двух суб-ЗЕЬЕСТ, как показано ниже, это feed_mode_idNULL, но результат для x.feed_mode_id должен быть таким, как показано в Query 1. Это я не понимаю, как эти комбинированные заявления работают.

SELECT 
    x.feed_mode_id, 
    IF (COUNT(y.answer_id) < 1, 0, 1) AS answered_question 
FROM 
    (SELECT 
     user.feed_mode_id 
    FROM 
     user 
    WHERE 
     user.id = 2) AS x, 
    (SELECT 
     answer.id AS answer_id 
    FROM 
     answer 
    WHERE 
     answer.question_id = (
      SELECT 
       question.id 
      FROM 
       question 
      ORDER BY 
       datetime_added_utc DESC 
      LIMIT 1 
     ) 
     AND answer.user_id = 2) AS y 

+--------------+-------------------+ 
| feed_mode_id | answered_question | 
+--------------+-------------------+ 
|   NULL |     0 | 
+--------------+-------------------+ 

Почему feed_mode_id производит NULL и не 1? Я открыт для разных подходов к повторной записи запроса в целом. Желательным результатом будет:

+--------------+-------------------+ 
| feed_mode_id | answered_question | 
+--------------+-------------------+ 
|   1 |     0 | 
+--------------+-------------------+ 

Это как-то связано с тем, что для этого случая пусто. В случаях, когда Query 2 возвращает значение (не пустое), комбинированный запрос работает по желанию.

+1

Можете ли вы сказать, какой результат вы хотите достичь после выполнения запроса? –

+0

* feed_mode_id * - это имя столбца, а не имя таблицы. Вы пытаетесь выбрать из столбца вместо таблицы. –

+0

Hi Hasib. Для первого подзапроса я выбираю из 'x', который является производной таблицей с одним столбцом и одним значением. Можете ли вы объяснить, что вы имеете в виду? Я не понимаю. – TPoy

ответ

1

У вас есть декартово произведение между x и y. Пока каждый из этих строк возвращает только одну строку, запрос возвращает одну строку.

Я рекомендую вам использовать синтаксис синтаксиса старой школы для операции соединения и вместо этого использовать ключевое слово JOIN.

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

Я не совсем понимаю, какие результаты вы на самом деле пытаетесь вернуть, но похоже, что вы определяете, указывает ли конкретный пользователь (однозначно идентифицированный столбцом «id» таблицы «пользователь») «ответ» на «последний добавленный вопрос».

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

SELECT u.feed_mode_id 
    , IF(COUNT(a.id) < 1, 0, 1) AS answered_question 
    FROM (SELECT q.id 
      FROM question q 
      ORDER BY q.datetime_added_utc DESC, q.id DESC 
      LIMIT 1 
     ) r 
    JOIN user u 
    ON u.id = 2 
    LEFT 
    JOIN answer a 
    ON a.user_id = u.id 
    AND a.question_id = r.id 
GROUP BY u.id 

ПРИМЕЧАНИЕ: вложенное представление с псевдонимом r возвращения id из «последних добавленных "question. (В исходном запросе, если два или более вопроса имеют одинаковый datetime_added_utc, неопределенная строка будет возвращена. Этот запрос делает это определением путем добавления другого выражения в предложение ORDER BY. (Запрос встроенного представления можно вытащить и запустить отдельно, чтобы убедиться, что возвращается ожидаемый результат.)

строка возвращается из r (если есть один), затем присоединились к ряду извлеченного из «пользователя» таблиц u. Мы предполагаем, что здесь, что id колонки в таблице «user» является уникальным идентификатором и, вероятно, основным ключом таблицы «user».

Если у нас есть «последний вопрос» (то есть строка от r), а ther e - строка из «user», которая соответствует предикату u.id=2 в предложении ON, то до сих пор мы гарантируем, что запрос вернет одну строку.

Далее мы выполняем операцию «внешнего соединения», чтобы найти соответствующие строки из таблицы «ответ». Предикаты в пункте ON ограничивают строки возвращены только те, которые имеют user_id Сопрягать id из u (в данном примере, эквивалентно заданию a.user_id=2, и имеющий question_id, который соответствует id из «наиболее недавно добавили» вопрос . r

LEFT ключевое слово идентифицирует это как «внешнее соединение», если нет соответствующих строк из таблицы «ответов», то запрос будет возвращать строку из r и u (Если бы это было внутреннее. join, то есть, если мы удалили ключевое слово LEFT, тогда, если не было соответствия ng строк из таблицы «ответ», тогда запрос не вернет строку.)

Мы добавим предложение GROUP BY u.id, если мы получим несколько совпадающих строк от answer; GROUP BY приводит к тому, что все строки с одинаковым значением u.id будут свернуты в одну строку.

Агрегат COUNT() подсчитывает количество ненулевых вхождений id из таблицы «ответ». Если бы не найдено подходящих строк, то a.id будет NULL, поэтому COUNT (a.id) возвращает 0.


Этот же запрос также будет работать, если мы искали Multipler пользователей, если мы задано несколько значений для user.id для соответствия, например

ON u.id IN (2,3,5,7) 

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

Но в любом из этих случаев мы также хотели бы добавить u.id AS user_id в список запросов SELECT, чтобы мы знали, какая строка была для какого пользователя.

Если мы хотим, чтобы вернуть два последние добавленные вопросы, мы могли бы изменить положение LIMIT в r, а затем добавить r.id к статье GROUP BY. Опять же, мы, вероятно, также захотели бы вернуть r.id AS question_id в список SELECT, поэтому мы знали, какая строка была для какого вопроса.

+0

Привет Спенсер. Точно верно, если пользователь ответил d самый последний вопрос - это то, что он ищет. Я даже не знал, что технически я делал JOIN, просто с другим синтаксисом. Интересно. Я узнаю много из этого объяснения. Запрос выглядит эффективно и прекрасно работает. Это очень ценится! Спасибо. – TPoy

+1

TPoy: синтаксис запятой - это то, что мы использовали, LONG time ago ... 'SELECT ... FROM b, a WHERE a.id = b.a_id', перед тем, как было введено ключевое слово JOIN. Просто замените эту запятую ключевым словом 'JOIN' и, возможно, переместите предикат в предложение' WHERE' в предложение 'ON'. (В этом простом примере просто замените 'WHERE' на' ON'. 'SELECT ... FROM b JOIN a ON b.id = a.b_id'. Это просто новый синтаксис для того же запроса. (Синтаксис запятой по-прежнему но старые теги, подобные мне, изучили новый синтаксис. – spencer7593

+0

Отлично. Я не знал этого. А что касается производных таблиц, я использую их много в других запросах. Пожелайте вернуться и переписать много других запросов в системе, что хорошо. Все в свое время. Еще раз спасибо! – TPoy

0

Точно запрос

SELECT 
    x.feed_mode_id, 
    IF (COUNT(y.answer_id) < 1, 0, 1) AS answered_question 
FROM 
    (SELECT 
     user.feed_mode_id 
    FROM 
     user 
    WHERE 
     user.id = 2) AS x, 
    (SELECT 
     answer.id AS answer_id 
    FROM 
     answer 
    WHERE 
     answer.question_id IN (
      SELECT 
       question.id 
      FROM 
       question 
      ORDER BY 
       datetime_added_utc DESC 
      LIMIT 1 
     ) 
     AND answer.user_id = 2) AS y 

answer.question_id = к answer.question_id В

+0

Спасибо, блюзовый. Я попытался (просто изменив 'answer.question_id =' на 'answer.question_id IN'), но он не поддерживается. Я использую 5.5.37. Результат: 'ERROR 1235 (42000): эта версия MySQL еще не поддерживает« LIMIT & IN/ALL/ANY/SOME subquery » – TPoy

+0

Поддерживает ли ваша MYSQL JOIN ??, если да, вы можете ПРИСОЕДИНИТЬСЯ, чтобы получить результат – bluesky

+0

И даже если бы это было подтверждено, заменив '=' на 'IN', это не изменило бы запрос. (Это LIMIT 1 в подзапросе, который позволяет использовать сравнение равенства, если этот подзапрос вернул более одной строки, MySQL будет вызывать другую ошибку. – spencer7593

0

Я не хотел, чтобы ответить на мой собственный вопрос, но я нашел решение, которое работает. Я переместил оператор IF в sub-SELECT, а не в первичный SELECT. Я не знаю, почему это работает, а предыдущая попытка - нет, но теперь он дает желаемый результат.

SELECT 
    x.feed_mode_id, 
    y.question_answered 
FROM 
    (SELECT 
     user.feed_mode_id 
    FROM 
     user 
    WHERE 
     user.id = 2) AS x, 
    (SELECT 
     IF (COUNT(answer.id < 1), 1, 0) AS question_answered 
    FROM 
     answer 
    WHERE 
     answer.question_id = (
      SELECT 
       question.id 
      FROM 
       question 
      ORDER BY 
       datetime_added_utc DESC 
      LIMIT 1 
     ) 
     AND answer.user_id = 2) AS y; 

+--------------+-------------------+ 
| feed_mode_id | question_answered | 
+--------------+-------------------+ 
|   1 |     0 | 
+--------------+-------------------+ 
+0

Этот запрос кажется более активным, чем требуется для возврата указанного набора результатов. Есть накладные расходы с материализацией каждой из производных таблиц, правда, это небольшие таблицы, и они собираются вписаться в память, поэтому мы не будем замечать проблему с производительностью, но мы склонны избегать производных таблиц, t some benefit. См. мой ответ для другого запроса, который возвращает результат, который, как я полагаю, вы ищете. (Отсутствуют некоторые данные образца, знание уникальности и нулеустойчивости столбцов. Я просто догадываюсь. – spencer7593

+0

У меня было ощущение, что это делая больше работы, чем нужно, хотя мое мышление все еще несколько грубо сработало с SQL. Спасибо за отличное объяснение. – TPoy

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