MySQL, как дать вывод объединения в предложение WHERE


У меня есть следующий SQL

SELECT tsd.ID
FROM test_series_details tsd
WHERE tsd.DIV_ID =1 
  AND tsd.END_DATE > NOW()
  AND tsd.ID NOT IN 
        ((SELECT tsr.TEST_ID
        FROM  test_series_results tsr
        WHERE tsr.STUDENT_ID=3)
    UNION 
        (SELECT tsrlv.TEST_ID
        FROM test_series_restore_log_viewer tsrlv
        WHERE tsrlv.STUDENT_ID=3
        GROUP BY tsrlv.TEST_ID))

Я протестировал нижеприведенную часть запроса, и она работает,

(SELECT tsr.TEST_ID
        FROM  test_series_results tsr
        WHERE tsr.STUDENT_ID=3)
    UNION 
        (SELECT tsrlv.TEST_ID
        FROM test_series_restore_log_viewer tsrlv
        WHERE tsrlv.STUDENT_ID=3
        GROUP BY tsrlv.TEST_ID)

Но как дать выход этого союза в состояние?

Ошибка заключается в следующем

Код Ошибки: 1064. У вас есть ошибка в синтаксисе SQL; проверьте руководство, которое соответствует вашей версии сервера MySQL для правой синтаксис для использования near ' UNION (выберите tsrlv.TEST_ID ОТ test_series_restore_log_viewer tsrlv ' в строке 9

4   2   2015-05-20 13:38:16

4 ответа:

Лучше всего написать это двумя отдельными предложениями:

SELECT tsd.ID
FROM test_series_details tsd
WHERE tsd.DIV_ID = 1 AND
      tsd.END_DATE > NOW() AND
      tsd.ID NOT IN (SELECT tsr.TEST_ID
                     FROM test_series_results tsr
                     WHERE tsr.STUDENT_ID = 3
                    ) AND
      tsd.ID NOT IN (SELECT tsrlv.TEST_ID
                     FROM test_series_restore_log_viewer tsrlv
                     WHERE tsrlv.STUDENT_ID = 3
                    );

Это позволяет механизму использовать преимущества индексов в двух таблицах. Кроме того, GROUP BY не является необходимым (либо при написании таким образом, либо в вашей первоначальной формулировке).

Для производительности - и просто на случай, если идентификаторы в подзапросах могут быть NULL - я был бы склонен написать это с помощью NOT EXISTS:

SELECT tsd.ID
FROM test_series_details tsd
WHERE tsd.DIV_ID = 1 AND
      tsd.END_DATE > NOW() AND
      NOT EXISTS (SELECT 1
                  FROM test_series_results tsr
                  WHERE tsr.STUDENT_ID = 3 and tsr.TEST_ID = tsd.ID
                 ) AND
      NOT EXISTS (SELECT 1
                  FROM test_series_restore_log_viewer tsrlv
                  WHERE tsrlv.STUDENT_ID = 3 and tsrlv.TEST_ID = tsd.ID
                 );

Наилучшими индексами для этого запроса являются: test_series_results(test_id, student_id) и test_series_restore_log_viewer(test_id, student_id) и test_series_details(DIV_ID, end_date, id).

Попробуйте использовать LEFT JOIN как показано ниже

SELECT tsd.ID
FROM test_series_details tsd
LEFT JOIN ((SELECT tsr.TEST_ID
        FROM  test_series_results tsr
        WHERE tsr.STUDENT_ID=3)
        UNION 
        (SELECT tsrlv.TEST_ID
        FROM test_series_restore_log_viewer tsrlv
        WHERE tsrlv.STUDENT_ID=3
        GROUP BY tsrlv.TEST_ID)) AS T on T.TEST_ID = tsd.ID 
WHERE tsd.DIV_ID =1 
  AND tsd.END_DATE > NOW()
  AND T.TEST_ID is null

Как насчет сейчас -

SELECT tsd.ID
FROM test_series_details tsd
WHERE 
tsd.DIV_ID =1 
AND tsd.END_DATE > NOW()
AND tsd.ID NOT IN (
   select TEST_ID from (
     (
        SELECT tsr.TEST_ID
        FROM  test_series_results tsr
        WHERE tsr.STUDENT_ID=3
     )
     UNION 
     (
        SELECT tsrlv.TEST_ID
        FROM test_series_restore_log_viewer tsrlv
        WHERE tsrlv.STUDENT_ID=3
        GROUP BY tsrlv.TEST_ID
     )
    )x
)

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

  SELECT tsd.ID
  FROM test_series_details tsd
  WHERE tsd.DIV_ID =1 
  AND tsd.END_DATE > NOW()
  AND tsd.ID NOT IN 
  (
      select  TEST_ID from (
       SELECT tsr.TEST_ID
       FROM  test_series_results tsr
       WHERE tsr.STUDENT_ID=3

       UNION 

       SELECT tsrlv.TEST_ID
       FROM test_series_restore_log_viewer tsrlv
       WHERE tsrlv.STUDENT_ID=3
       GROUP BY tsrlv.TEST_ID   
     )as alias 
   )