Нужна помощь с правильным SQL

Так что я новичок, начинающий, начинающий - брось все вышеперечисленное в меня. Я пытаюсь создать запрос, который будет искать в базе данных и возвращать бла-бла-бла. Проблема в том, что это не совсем работает. Вот пример запроса - Как вы видите, помимо прочего я пытаюсь вернуть результаты от кого-то с фамилией Джонсон

SELECT BookingInfo.ClinicID, BookingInfo.BookingDate, BookingInfo.BookingTime, 
  BookingInfo.Status, PatientBooking.FirstName, PatientBooking.LastName, 
  PatientBooking.DateOfBirth 
FROM BookingInfo LEFT JOIN PatientBooking 
  ON BookingInfo.PatientID = PatientBooking.PatientID 
WHERE PatientBooking.LastName = 'Johnson' AND BookingInfo.ClinicID = '1' 
  OR BookingInfo.ClinicID = '2' 
ORDER BY BookingInfo.BookingDate DESC 

Это возвращает результаты с Джонсоном, но и с другими. Другая:

SELECT BookingInfo.ClinicID, BookingInfo.BookingDate, BookingInfo.BookingTime, 
  BookingInfo.Status, PatientBooking.FirstName, PatientBooking.LastName, 
  PatientBooking.DateOfBirth 
FROM BookingInfo LEFT JOIN PatientBooking 
  ON BookingInfo.PatientID = PatientBooking.PatientID 
WHERE BookingInfo.BookingDate = '05-18-2010' AND BookingInfo.ClinicID = '1' 
  OR BookingInfo.ClinicID = '2' 
ORDER BY BookingInfo.BookingDate DESC 

Это возвращает результаты с указанной мной даты, но также и другие. Что-то не так с моим синтаксисом? Разве я понятия не имею, что я делаю? Пожалуйста, помогите новичку. Спасибо!

5 ответов

Решение

Кредит должен пойти в @Randolph Potter:

SELECT BookingInfo.ClinicID, BookingInfo.BookingDate, BookingInfo.BookingTime, BookingInfo.Status, PatientBooking.FirstName, PatientBooking.LastName, PatientBooking.DateOfBirth 
FROM BookingInfo 
    LEFT JOIN PatientBooking ON BookingInfo.PatientID = PatientBooking.PatientID 
WHERE 
    BookingInfo.BookingDate = '05-18-2010' AND 
    ( BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2' ) 
ORDER BY BookingInfo.BookingDate DESC 

Просмотрите порядок приоритета между AND и OR.

В арифметике умножение имеет более высокий приоритет, чем сложение.

Пример: 10+10*10 = 110, но (10+10)*10 = 200.

Это похоже на И и ИЛИ. И имеет более высокий приоритет, чем ИЛИ, так что без скобок:

WHERE BookingInfo.BookingDate = '05-18-2010' AND BookingInfo.ClinicID = '1' 
  OR BookingInfo.ClinicID = '2'

работает так:

WHERE (BookingInfo.BookingDate = '05-18-2010' AND BookingInfo.ClinicID = '1') 
  OR BookingInfo.ClinicID = '2'

Но вы хотите, чтобы это работало так:

WHERE BookingInfo.BookingDate = '05-18-2010' AND 
  (BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2')

Поэтому поставьте скобки, чтобы убедиться, что порядок старшинства работает так, как вы хотите.


Я также только что заметил, что вы используете даты в формате MM-DD-YYYY, которые не распознаются MySQL для литералов даты. Вы должны использовать формат ГГГГ-ММ-ДД. Это может быть причиной другой проблемы.

SELECT DATE('05-18-2010'); -- returns NULL
SELECT DATE('2010-05-18'); -- returns 2010-05-18

Re ваш комментарий:

Вы уверены, что AND имеет более высокий приоритет?

Да, я уверен, что И имеет более высокий приоритет, чем ИЛИ. С одной стороны, иерархия приоритета всех операторов в MySQL документирована здесь: http://dev.mysql.com/doc/refman/5.1/en/operator-precedence.html

Давайте рассмотрим пример с использованием вашей первоначально заявленной проблемы:

BookingDate   ClinicID 
2010-05-18    2
2008-05-18    2

WHERE BookingInfo.BookingDate = '2010-05-18' AND 
  BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2'

Используя это выражение, должен совпадать только первый ряд. Но вы обнаружили, что обе строки совпадают, хотя дата второй строки не верна. Зачем? Давайте заменим каждое сравнение на ИСТИНА или ЛОЖЬ:

TRUE AND FALSE OR TRUE
FALSE AND FALSE OR TRUE

Если бы OR имело более высокий приоритет, оно было бы оценено следующим образом:

TRUE AND (FALSE OR TRUE)
FALSE AND (FALSE OR TRUE)

Поскольку любое значение, объединенное с ИЛИ ИСТИНА, дает ИСТИНА, подвыражение в этих скобках будет сокращено до:

TRUE AND (TRUE)
FALSE AND (TRUE)

И вторая строка не будет соответствовать, потому что ЛОЖЬ И ИСТИНА дает ЛОЖЬ. Но этого не может быть, так как вы обнаружили, что второй ряд неверно совпадает.

Фактически, AND имеет более высокий приоритет, чем OR, поэтому он действительно оценивает, как если бы вы имели круглые скобки вокруг подвыражения AND:

(TRUE AND FALSE) OR TRUE
(FALSE AND FALSE) OR TRUE

Что сводится к:

(FALSE) OR TRUE
(FALSE) OR TRUE

В обоих случаях FALSE OR TRUE выдает TRUE, и обе строки совпадают.

Таким образом, без скобок семантика по умолчанию состоит в том, что AND имеет более высокий приоритет, чем OR. Вам нужны скобки:

WHERE BookingInfo.BookingDate = '2010-05-18' AND 
  (BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2')

Это, вероятно, потому что у вас нет круглых скобок вокруг вашего условия OR. Попробуйте обновленную версию ниже:

SELECT BookingInfo.ClinicID, 
       BookingInfo.BookingDate, 
       BookingInfo.BookingTime,
       BookingInfo.Status, 
       PatientBooking.FirstName, 
       PatientBooking.LastName, 
       PatientBooking.DateOfBirth 
FROM       BookingInfo 
LEFT JOIN  PatientBooking 
ON         BookingInfo.PatientID = PatientBooking.PatientID 
WHERE      PatientBooking.LastName = 'Johnson' 
AND        BookingInfo.ClinicID IN ('1', '2') 
ORDER BY   BookingInfo.BookingDate DESC 

Кроме того, добавление небольшого форматирования в ваш SQL сделает его более читабельным. Это поможет вам получить ответы на SO, а также поможет всем, кто в конечном итоге изучит ваш код.

Вы должны добавить скобки вокруг части WHERE пункт, который предшествует OR, В первом примере вы имеете в виду

SELECT
    BookingInfo.ClinicID,
    BookingInfo.BookingDate,
    BookingInfo.BookingTime,
    BookingInfo.Status,
    PatientBooking.FirstName,
    PatientBooking.LastName,
    PatientBooking.DateOfBirth
FROM
    BookingInfo
    LEFT JOIN PatientBooking ON BookingInfo.PatientID = PatientBooking.PatientID
WHERE
    PatientBooking.LastName = 'Johnson' AND
    ( BookingInfo.ClinicID = '1' OR
      BookingInfo.ClinicID = '2'
      )
ORDER BY
    BookingInfo.BookingDate DESC

но потому что AND имеет более высокий приоритет, чем ORчто вы на самом деле делаете

SELECT
    BookingInfo.ClinicID,
    BookingInfo.BookingDate,
    BookingInfo.BookingTime,
    BookingInfo.Status,
    PatientBooking.FirstName,
    PatientBooking.LastName,
    PatientBooking.DateOfBirth
FROM
    BookingInfo
    LEFT JOIN PatientBooking ON BookingInfo.PatientID = PatientBooking.PatientID
WHERE
    ( PatientBooking.LastName = 'Johnson' AND
      BookingInfo.ClinicID = '1'
      ) OR
    BookingInfo.ClinicID = '2'
ORDER BY
    BookingInfo.BookingDate DESC

Таким образом, вы увидите каждую строку, в которой ClinicID равно 2; не только Джонсона.

Если вы поставите скобки вокруг 2 условий ClinicID, это должно сработать.

Увидеть ниже:

SELECT BookingInfo.ClinicID, BookingInfo.BookingDate, BookingInfo.BookingTime, BookingInfo.Status, PatientBooking.FirstName, PatientBooking.LastName, PatientBooking.DateOfBirth FROM BookingInfo LEFT JOIN PatientBooking ON BookingInfo.PatientID = PatientBooking.PatientID WHERE PatientBooking.LastName = 'Johnson' AND (BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2') ORDER BY BookingInfo.BookingDate DESC 

SELECT BookingInfo.ClinicID, BookingInfo.BookingDate, BookingInfo.BookingTime, BookingInfo.Status, PatientBooking.FirstName, PatientBooking.LastName, PatientBooking.DateOfBirth FROM BookingInfo LEFT JOIN PatientBooking ON BookingInfo.PatientID = PatientBooking.PatientID WHERE BookingInfo.BookingDate = '05-18-2010' AND (BookingInfo.ClinicID = '1' OR BookingInfo.ClinicID = '2') ORDER BY BookingInfo.BookingDate DESC 
Другие вопросы по тегам