Условный оператор WHERE

Ситуация, когда требуется сделать выборку по определённому условию, встречается очень часто. Для этого в операторе SELECT существует оператор WHERE, после которого следуют условия для ограничения строк. Если запись удовлетворяет этому условию, то попадает в результат, иначе отбрасывается.

Общая структура запроса с оператором WHERE

MySQL 8.1
SELECT [DISTINCT] поля_таблиц FROM наименование_таблицы
WHERE условие_на_ограничение_строк
[логический_оператор другое_условие_на_ограничение_строк];

Например, запрос с использованием оператора WHERE может выглядеть следующим образом:

MySQL 8.1
SELECT * FROM Student
WHERE first_name = "Grigorij" AND YEAR(birthday) > 2000;
MySQL 8.1
SELECT * FROM Student
WHERE first_name = 'Grigorij' AND EXTRACT(YEAR FROM birthday) > 2000;
idfirst_namemiddle_namelast_namebirthdayaddress
33GrigorijGennadevichKapustin2001-12-13T00:00:00.000Zul. Pervomajskaya, d. 45, kv. 6
65GrigorijKirillovichKolobov2003-07-17T00:00:00.000Zul. CHernova, d. 9, kv. 34

В этом примере мы используем сразу два условия:

  • first_name = "Grigorij" — имя студента должно быть «Grigorij»
  • YEAR(birthday) > 2000 — год рождения больше 2000
  • first_name = 'Grigorij' — имя студента должно быть «Grigorij»
  • EXTRACT(YEAR FROM birthday) > 2000 — год рождения больше 2000

Между ними стоит логический оператор AND, который требует, чтобы оба условия выполнялись одновременно. В результате мы получаем только тех студентов, которые подходят под оба критерия.

Операторы сравнения

Чтобы сравнивать значения в SQL, используются специальные операторы. Они позволяют проверить, равны ли значения, больше ли одно другого, не равны ли они и так далее. Результатом сравнения может быть:

  • true (это то же самое, что 1)
  • false (то же, что 0)
  • NULL (если результат сравнения не определён, например, при сравнении с NULL)
ОператорОбозначениеОписание
Равенство=Если оба значения равны, то результат будет равен 1, иначе 0
Эквивалентность<=>Аналогичен оператору равенства, за исключением того, что результат будет равен 1 в случае сравнения NULL с NULL и 0, когда идёт сравнение любого значения с NULL
Неравенство<> или !=Если оба значения не равны, то результат будет равен 1, иначе 0
Меньше<Если одно значение меньше другого, то результат будет равен 1, иначе 0
Меньше или равно<=Если одно значение меньше или равно другому, то результат будет равен 1, иначе 0
Больше>Если одно значение больше другого, то результат будет равен 1, иначе 0
Больше или равно>=Если одно значение больше или равно другому, то результат будет равен 1, иначе 0

Результатом сравнения любого значения с NULL является NULL. Исключением является оператор эквивалентности.

ОператорОбозначениеОписание
Равенство=Если оба значения равны, то результат будет равен true, иначе false
Неравенство<> или !=Если оба значения не равны, то результат будет равен true, иначе false
Меньше<Если одно значение меньше другого, то результат будет равен true, иначе false
Меньше или равно<=Если одно значение меньше или равно другому, то результат будет равен true, иначе false
Больше>Если одно значение больше другого, то результат будет равен true, иначе false
Больше или равно>=Если одно значение больше или равно другому, то результат будет равен true, иначе false

Результатом сравнения любого значения с NULL является NULL.

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

MySQL 8.1
SELECT
    2 = 1,
	'a' = 'a',
    1 <=> NULL,
	NULL <=> NULL,
	2 <> 2,
	3 < 4,
	10 <= 10,
	7 > 1,
	8 >= 10;
2 = 1'a' = 'a'1 <=> NULLNULL <=> NULL2 <> 23 < 410 <= 107 > 18 >= 10
010101110
MySQL 8.1
SELECT
    2 = 1,
	'a' = 'a',
	2 <> 2,
	3 < 4,
	10 <= 10,
	7 > 1,
	8 >= 10;
2 = 1'a' = 'a'2 <> 23 < 410 <= 107 > 18 >= 10
falsetruefalsetruetruetruefalse

Логические операторы

Логические операторы — это ваши помощники, когда нужно объединить несколько условий в одном SQL-запросе. С их помощью вы можете гибко выбирать только те строки, которые вам действительно нужны. Давайте посмотрим как это работает на практике:

  • AND — оба условия должны быть верны.

    Представьте, что вы ищете рейсы, которые одновременно соответствуют двум требованиям: например, самолёт должен быть определённой модели, и вылетать не из какого-то города. Оператор AND помогает объединить эти условия.

    MySQL 8.1
    SELECT * FROM Trip
    WHERE plane = 'Boeing' AND town_from = 'London';
    
    MySQL 8.1
    SELECT * FROM Trip
    WHERE plane = 'Boeing' AND town_from = 'London';
    
    idcompanyplanetown_fromtown_totime_outtime_in
    77715BoeingLondonSingapore1900-01-01T01:00:00.000Z1900-01-01T11:00:00.000Z
    77735BoeingLondonSingapore1900-01-01T03:00:00.000Z1900-01-01T13:00:00.000Z
    77755BoeingLondonSingapore1900-01-01T09:00:00.000Z1900-01-01T20:00:00.000Z
    77775BoeingLondonSingapore1900-01-01T18:00:00.000Z1900-01-02T06:00:00.000Z
    88815BoeingLondonParis1900-01-01T03:00:00.000Z1900-01-01T04:00:00.000Z

    Такой запрос выберет только те рейсы, где модель самолёта — Boeing и город вылета — London.

    Если хотя бы одно из условий не выполняется (например, самолёт не Boeing или вылет не из London), такой рейс не попадёт в результат.

  • OR — достаточно, чтобы выполнилось хотя бы одно условие.

    Оператор OR работает как "или". Если хотя бы одно из условий верно — строка попадёт в результат. Это удобно, когда вы хотите увидеть все рейсы, которые соответствуют хотя бы одному из ваших критериев.

    MySQL 8.1
    SELECT * FROM Trip
    WHERE town_to = 'Paris' OR plane = 'Airbus';
    
    MySQL 8.1
    SELECT * FROM Trip
    WHERE town_to = 'Paris' OR plane = 'Airbus';
    
    idcompanyplanetown_fromtown_totime_outtime_in
    11004BoeingRostovParis1900-01-01T14:30:00.000Z1900-01-01T17:50:00.000Z
    88815BoeingLondonParis1900-01-01T03:00:00.000Z1900-01-01T04:00:00.000Z

    В результате вы получите все рейсы, которые прилетают в Paris, а также все рейсы на самолёте Airbus (даже если они летят не в Paris).

    Если рейс и на Airbus, и в Paris — он тоже попадёт в результат.

  • NOT — условие становится противоположным.

    Оператор NOT инвертирует условие: если оно было истинным, станет ложным, и наоборот. Это удобно, когда вы хотите исключить какие-то значения.

    MySQL 8.1
    SELECT * FROM Trip WHERE NOT town_to = 'Moscow';
    
    MySQL 8.1
    SELECT * FROM Trip WHERE NOT town_to = 'Moscow';
    

    Такой запрос выберет все рейсы, которые прилетают не в Moscow.

    То есть, если город прилёта — Moscow, такой рейс не попадёт в результат. Всё остальное — попадёт.

  • XOR — это оператор, который помогает выбрать строки, где выполняется только одно из двух условий, но не оба сразу.

    Допустим, вы хотите найти рейсы, которые или вылетают из Moscow, или прилетают в Paris, но не оба варианта сразу. Давайте посмотрим на все возможные случаи:

    Вылетает
    из Moscow
    Прилетает
    в Paris
    Попадёт
    в результат
    Объяснение
    ДаНет✅ ДаВыполняется только первое условие
    НетДа✅ ДаВыполняется только второе условие
    ДаДа❌ НетВыполняются оба условия — XOR исключает такие случаи
    НетНет❌ НетНе выполняется ни одно условие
    MySQL 8.1
    SELECT * FROM trip
    WHERE town_from = 'Moscow' XOR town_to = 'Paris';
    
    MySQL 8.1
    SELECT * FROM trip
    WHERE (town_from = 'Moscow' AND town_to != 'Paris')
       OR (town_from != 'Moscow' AND town_to = 'Paris');
    

    Обратите внимание: оператор XOR есть не во всех базах данных. Если его нет, можно обойтись комбинацией AND и OR.

    В PostgreSQL нет оператора XOR, поэтому используется комбинация AND и OR для достижения того же результата.

Приоритет логических операторов

Когда вы пишете запрос с несколькими условиями, SQL должен понять, в каком порядке их проверять. Это похоже на математику: сначала умножение, потом сложение. Для логических операторов в SQL тоже есть свой порядок — это называется приоритетом.

  • Сначала — NOT
  • Затем — AND
  • Потом — XOR
  • В конце — OR

Почему это важно?

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

Посмотрим на такой пример:

MySQL 8.1
SELECT *
FROM Trip
WHERE town_to = 'Paris'
	OR plane = 'Boeing'
	AND NOT town_from = 'Moscow';
MySQL 8.1
SELECT *
FROM Trip
WHERE town_to = 'Paris'
	OR plane = 'Boeing'
	AND NOT town_from = 'Moscow';
idcompanyplanetown_fromtown_totime_outtime_in
11004BoeingRostovParis1900-01-01T14:30:00.000Z1900-01-01T17:50:00.000Z
11014BoeingParisRostov1900-01-01T08:12:00.000Z1900-01-01T11:45:00.000Z
77715BoeingLondonSingapore1900-01-01T01:00:00.000Z1900-01-01T11:00:00.000Z
77725BoeingSingaporeLondon1900-01-01T12:00:00.000Z1900-01-02T02:00:00.000Z
77735BoeingLondonSingapore1900-01-01T03:00:00.000Z1900-01-01T13:00:00.000Z
77745BoeingSingaporeLondon1900-01-01T14:00:00.000Z1900-01-02T06:00:00.000Z
77755BoeingLondonSingapore1900-01-01T09:00:00.000Z1900-01-01T20:00:00.000Z
77765BoeingSingaporeLondon1900-01-01T18:00:00.000Z1900-01-02T08:00:00.000Z
77775BoeingLondonSingapore1900-01-01T18:00:00.000Z1900-01-02T06:00:00.000Z
77785BoeingSingaporeLondon1900-01-01T22:00:00.000Z1900-01-02T12:00:00.000Z
88815BoeingLondonParis1900-01-01T03:00:00.000Z1900-01-01T04:00:00.000Z
88825BoeingParisLondon1900-01-01T22:00:00.000Z1900-01-01T23:00:00.000Z

Что здесь происходит:

  • Сначала проверяется, что рейс не из Moscow (NOT town_from = 'Moscow').

  • Затем смотрится, что самолёт — Boeing, и объединяется это с первым условием через AND, то есть, ищутся рейсы, которые не из Moscow и на Boeing (plane = 'Boeing' AND NOT town_from = 'Moscow')

  • Потом к результату добавляются все рейсы, которые прилетают в Paris, даже если они не на Boeing и вылетают из Moscow (town_to = 'Paris' OR ...).

В итоге получится следующая выборка:

  • Все рейсы, которые не из Moscow и на Boeing
  • А ещё все рейсы, которые прилетают в Paris

Если вы хотите изменить порядок проверки условий или сделать его более понятным, используйте скобки. Всё, что в скобках, выполняется в первую очередь. К примеру, если вручную расставить скобки согласно приоритетам логических операторов, то сразу становится понятно, как будет выполняться запрос!

MySQL 8.1
SELECT *
FROM Trip
WHERE (
		town_to = 'Paris'
		OR (
			plane = 'Boeing'
			AND (NOT town_from = 'Moscow')
		)
	);
MySQL 8.1
SELECT *
FROM Trip
WHERE (
		town_to = 'Paris'
		OR (
			plane = 'Boeing'
			AND (NOT town_from = 'Moscow')
		)
	);

А теперь попробуйте сами: допустим, вы хотите получить список рейсов, которые вылетают из Paris или на самолёте Boeing, и летят не в Moscow. Это можно сделать правильно расставив скобки в исходном запросе из примера. Как бы вы это сделали?