Подтвердить что ты не робот

Результат неправильных результатов MYSQL

У меня есть 3 таблицы со следующими данными:

Первая таблица называется соединениями, где connections.username1 является тем, кто следует, и connections.username2 является тем, за которым следует.

Он имеет следующие строки:

connections.username1 | connections.username2
      mikha           |          guy
      guy             |          maricela
      maricela        |          guy

Вторая таблица называется вопросами. У него есть столбец для искателя под названием questions.asker_username, а другой для того, кто получает вопрос под названием questions.target_username. Когда азбуку называют "sys.tem" и целевой объект "every.one", он рассматривает глобальный вопрос и может быть ответен всеми членами.

Анонимные пользователи могут спросить, и их ip записывается как asker_username.

Он имеет следующие строки:

questions.id | questions.asker_username | questions.target_username | questions.question
  1          |      mikha               |       guy                 | what your name?                             
  2          |      mikha               |       maricela            | What your age?
  3          |      guy                 |       mikha               | what your name?
  4          |      maricela            |       guy                 | favorite food?
  5          |      xx.xx.xxx.xx        |       mikha               | favorite pet?
  6          |      xx.xx.xxx.xx        |       guy                 | first name?
  7          |      xx.xx.xxx.xx        |       maricela            | first name?   
  8          |      sys.tem             |       every.one           | what ur name?
  9          |      sys.tem             |       every.one           | favorite movie?  
 10          |      sys.tem             |       every.one           | favorite game? 

Третья таблица называется ответами. Идентификатор в таблице ответов совпадает с идентификатором вопроса. В этой таблице есть столбец для идентификатора и имени пользователя и ответа.

answers.id  |  answers.username | answers.answer
   1        |       guy         | my name is guy
   2        |     maricela      | my name is maricela
   3        |       mikha       | my name is mikha
   4        |       guy         | pizza        
   8        |       guy         | guy is my name
   8        |       maricela    | maricela is my name   
   9        |       maricela    | avatar

Мне нужен запрос, который объединяет следующие условия, связанные с "mikha" и людьми, которых он следует:

1) questions.asker_username НЕ "mikha"

2) questions.target_username является либо "mikha" , либо любым из пользователей, которых он следует.

3) Если questions.target_username равно "every.one" и отвечает "mikha" , покажите вопрос.

4) Если questions.target_username равно "каждому" и отвечает любой из тех, кого "миха" следует, покажите вопрос и ответ. Если нет ответов пользователей, которых "mikha" следует, не показывайте вопрос.

5) Если questions.target_username равно "every.one" и никому не отвечает, покажите вопрос один раз.

6) Если questions.target_username равно "every.one" и на него не отвечает "mikha" и не отвечает ни один из людей, которых он следует, покажите этот вопрос только один раз.

Я использую следующий запрос:

SELECT questions.id,answers.id,questions.asker_username,questions.target_username,
    answers.username,questions.question,answers.answer 
FROM questions 
    LEFT JOIN answers ON (questions.id = answers.id) 
    LEFT JOIN connections ON connections.username1 = 'mikha' 
        AND (questions.target_username = connections.username2 
            OR questions.asker_username = connections.username2 
            OR connections.username2 = answers.username) 
WHERE questions.asker_username <> 'mikha' 
    AND (questions.target_username = 'mikha' 
        OR questions.target_username = connections.username2 
        OR (questions.target_username = 'every.one' 
            AND (answers.username = 'mikha' 
                OR answers.username = connections.username2
                OR answers.username IS NULL)
            )
        ) 
GROUP BY questions.id,answers.username

Ожидаемый результат:

questions.id | answers.id | questions.asker_username | questions.target_username | answers.username | questions.question | answers.answer
    3        |      3     |        guy               |          mikha            |    mikha         | what your name?  | my name is mikha
    4        |      4     |        maricela          |          guy              |    guy           | favorite food?     | pizza
    5        |      5     |        xx.xx.xxx.xx      |          mikha            |    NULL          | favorite pet?      | NULL
    6        |      6     |        xx.xx.xxx.xx      |          guy              |    NULL          | first name?        | NULL        
    8        |      8     |        sys.tem           |         every.one         |    NULL          | what ur name?    | NULL 
    8        |      8     |        sys.tem           |         every.one         |    guy           | what ur name?    | guy is my name
    9        |      9     |        sys.tem           |         every.one         |    NULL          | favorite movie?    | NULL       
    10       |      10    |        sys.tem           |         every.one         |    NULL          | favorite game?     | NULL 

В результате я получаю:

 questions.id | answers.id | questions.asker_username | questions.target_username | answers.username | questions.question | answers.answer
    3        |      3     |        guy               |          mikha            |    mikha         | what your name?  | my name is mikha
    4        |      4     |        maricela          |          guy              |    guy           | favorite food?     | pizza
    5        |      5     |        xx.xx.xxx.xx      |          mikha            |    NULL          | favorite pet?      | NULL
    6        |      6     |        xx.xx.xxx.xx      |          guy              |    NULL          | first name?        | NULL        
    8        |      8     |        sys.tem           |         every.one         |    guy           | what ur name?    | guy is my name           
    10       |      10    |        sys.tem           |         every.one         |    NULL          | favorite game?     | NULL 

Я построил схему http://sqlfiddle.com/#!2/29929e/1, чтобы показать результаты, которые я действительно получаю

Спасибо:)

4b9b3361

Ответ 1

Проблема заключается в том, что в некоторых случаях вы хотите дважды задать вопрос, когда существует только один соответствующий ответ. Я цитирую:

Итак, я хочу показать его только один раз для "mikha", ответил ли он или нет, и показывать его снова каждый раз, когда он отвечает любым из людей, "mikha" следует за

Это дублирование делает вещи довольно сложными.

Я попытался решить это с помощью UNION и, похоже, работает. Тем не менее, я до сих пор не полностью понял ваши требования...

В любом случае, здесь мы идем:

select * from
(
  select
    q.id as q_id, a.id as a_id, q.asker_username,
    q.target_username, a.username, q.question, a.answer
  from
    questions q
    left outer join answers a on q.id = a.id
  where
    q.asker_username <> 'mikha' 
    and
    (
      q.target_username = 'mikha'
      or q.target_username in
         (select username2 from connections where username1 = 'mikha')
      or
      (
        q.target_username = 'every.one'
        and
        (
          a.username = 'mikha'
          or a.username in
             (select username2 from connections where username1 = 'mikha')
          or a.id is null
        )
      )
    )
  union
  select
    q.id as q_id, NULL as a_id, q.asker_username,
    q.target_username, NULL, q.question, NULL
  from
    questions q
  where
    q.asker_username <> 'mikha' 
    and q.target_username = 'every.one'
    and not exists (select id
                    from answers
                    where
                      id = q.id
                      and username = 'mikha'
                    )
) r
order by q_id;

Протестируйте его в прямом эфире:
С ответом от mikha на вопрос 8
Без ответа от mikha для вопроса 8

Ответ 2

ОК, давайте начнем с самого простого (ваше первое правило):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id  
WHERE q.asker_username <> 'mikha' 
GROUP BY q.id,a.username

Теперь добавим второе правило - теперь добавляется больше сложности...

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
GROUP BY q.id,a.username

Теперь третье правило (для всех ответило mikha):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
GROUP BY q.id,a.username

Теперь для четвертого правила:

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
GROUP BY q.id,a.username

Пятое правило (Иисус!):

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
        OR (q.target_username = 'every.one' AND a.answer IS NULL)
GROUP BY q.id,a.username

И для последнего:

SELECT q.id, a.id, q.asker_username, q.target_username, a.username, q.question, a.answer 
FROM questions q 
    LEFT JOIN answers a ON q.id = a.id 
WHERE q.asker_username <> 'mikha' 
    AND q.target_username = 'mikha' 
        OR q.target_username IN (
            SELECT username2 
            FROM connections 
            WHERE username1 = 'mikha'
        )
        OR (q.target_username = 'every.one' AND a.username = 'mikha')
        OR (q.target_username = 'every.one' AND a.username IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
        OR (q.target_username = 'every.one' AND a.answer IS NULL)
        OR (q.target_username = 'every.one' AND a.username NOT IN (
            SELECT username2 
            FROM connections 
                INNER JOIN answers ON answers.username = connections.username2
                    AND answers.answers IS NOT NULL
            WHERE username1 = 'mikha'
        ))
GROUP BY q.id,a.username

Я думаю, что правило 4 и правило 6 взаимно противоположны друг другу (что противоречит сказанному), а при использовании в одном запросе он будет иметь тот же эффект, что и опустить...

Я не тестировал ни одного из запросов, но я считаю, что они работают.

Ответ 3

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

В приведенном ниже коде приведены встроенные комментарии к тому, что он делает. Я также согласился бы с другими ответами, предлагая, чтобы числовые поля id были лучше для сравнений, - и я также советую помещать уникальное поле rowid в таблицу ответов (лучше, измените id на question_id), а затем сделайте id уникальное поле.

SELECT DISTINCT q.id,a.id,q.asker_username,q.target_username,a.username,q.question,a.answer
FROM questions q
  /* Answers */
  LEFT JOIN answers a ON (q.id=a.id)
  /* connection entries where the person being followed is the target */
  LEFT JOIN (SELECT username2 FROM connections WHERE username1='mikha') c_q
    ON c_q.username2=q.target_username
  /* connection entries where the person being followed answered the question */
  LEFT JOIN (SELECT username2 FROM connections WHERE username1='mikha') c_a
    ON c_a.username2=a.username 
  /* Own answers */
  LEFT JOIN (SELECT id FROM answers WHERE username='mikha') a_own 
    ON (q.id=a_own.id) 
  WHERE 
  /* Asker not mikha, target is mikha or followed user - rules 1,2 */
  (q.asker_username <> 'mikha'
  AND (q.target_username='mikha' OR c_q.username2 IS NOT NULL))
  OR
  /* sys.tem/every.one, answered by mikha - rule 3 */
  (q.target_username='every.one' AND a.username='mikha')
  OR
  /* Rules 4, 5 & 6 combine to give "show the answer at least once, and once for every followed user who answered" - here we select any every.one messages where mikha didn't answer and nor did the people he follows */
  (q.target_username='every.one' AND a_own.id IS NULL AND c_a.username2 IS NULL);

Это не дает вам двух строк для вопроса 8, но я не мог понять, почему вы этого хотели. Проблема в том, что неясно, какие из ваших правил являются аддитивными и которые являются комбинационными. Если вы можете объяснить, какие правила должны "добавлять" строку, а не просто предоставлять другую причину для отображения строки, возможно, мы также можем получить эту дополнительную строку для вопроса 8.