Нужна помощь с правильным 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