Функции и выражения: строки, даты, CASE
Курс MS SQL с нуля · Урок 9 из 12 · Часть 3. Изменение и проектирование
Урок собирает рабочий набор встроенных функций и два мощных выражения курса: CASE и связку COALESCE с ISNULL. Цель — вычисляемые колонки отчётного качества и предсказуемость на NULL.
Перед уроком база обязана быть чистой: если проходили урок изменения данных, восстановите TechStore скриптами урока 2.
Содержание
1. Что вы освоите
К концу урока вы:
- склеиваете строки без NULL-обнуления через CONCAT;
- вырезаете подстроки по позиции разделителя без «магических» чисел;
- двигаете и сравниваете даты через DATEADD и DATEDIFF с оговорками;
- ветвите выражения поисковым CASE и ставите ELSE осознанно;
- выбираете COALESCE против ISNULL и объясняете различие типов.
2. Строковые функции
| Функция | Результат | Замечание |
|---|---|---|
| CONCAT(a, b) | склейка с NULL-иммунитетом | стандартная форма курса |
| LEFT, RIGHT, SUBSTRING | куски строки по позициям | индексация с единицы |
| CHARINDEX(искомое, строка) | позиция подстроки, ноль — не нашлось | для вырезания по разделителю |
| UPPER, LOWER, TRIM | регистр и пробелы | для нормализации входа |
| REPLACE | замена вхождений | в цепочках при чистке |
| LEN и DATALENGTH | знаки без правых пробелов и байты | не путать их |
Чистый код
SELECT CONCAT(p.Name, N' (', cat.Name, N') — ',
CAST(p.Price AS NVARCHAR(20)), N' ₽') AS product_label
FROM dbo.Products AS p
JOIN dbo.Categories AS cat ON cat.CategoryID = p.CategoryID;
SELECT c.Email,
LEFT(c.Email, CHARINDEX(N'@', c.Email) - 1) AS login_part
FROM dbo.Customers AS c
WHERE CHARINDEX(N'@', c.Email) BETWEEN 2 AND 2000;
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
SELECT CONCAT(p.Name, N' (', cat.Name, N') — ', CAST(p.Price AS NVARCHAR(20)), N' ₽') AS product_label -- → склейка CONCAT: NULL в любом слагаемом не гасит строку FROM dbo.Products AS p JOIN dbo.Categories AS cat ON cat.CategoryID = p.CategoryID; SELECT c.Email, LEFT(c.Email, CHARINDEX(N'@', c.Email) - 1) AS login_part -- → логин: всё слева от «собаки»; индексация строк с единицы FROM dbo.Customers AS c WHERE CHARINDEX(N'@', c.Email) BETWEEN 2 AND 2000; -- → ноль означает «не нашлось»: такие адреса отсекаются фильтромSQL
3. Функции дат
| Функция | Результат | Подвохи |
|---|---|---|
| SYSDATETIME() | текущие дата-время сервера | точность до 100 нс |
| DATEADD(d, n, x) | сдвиг даты на n единиц d | високосность сам учтена |
| DATEDIFF(d, a, b) | число пересечённых границ d | не «полные сутки» |
| DATEPART(weekday, x) | часть даты числом | зависит от SET DATEFIRST |
| EOMONTH(x) | последний день месяца | со сдвигом второго аргумента |
| CAST(x AS date) | чистая дата без времени | для календарных срезов |
4. CASE и связка COALESCE
CASE — выражение, а не оператор: его результат присваивается алиасом, ставится в WHERE, GROUP BY и даже в агрегат. Поисковая форма универсальна:
Чистый код
SELECT check_class, COUNT(*) AS orders_cnt
FROM (
SELECT CASE
WHEN o.TotalAmount BETWEEN 100000 AND 999999999 THEN N'крупный'
WHEN o.TotalAmount BETWEEN 50000 AND 99999 THEN N'средний'
ELSE N'малый'
END AS check_class
FROM dbo.Orders AS o
) AS classified
GROUP BY check_class
ORDER BY orders_cnt DESC;
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
SELECT check_class, COUNT(*) AS orders_cnt -- → итоговый отчёт: три класса и число заказов в каждом FROM ( SELECT CASE WHEN o.TotalAmount BETWEEN 100000 AND 999999999 THEN N'крупный' -- → самый широкий коридор первым: проверка сверху вниз WHEN o.TotalAmount BETWEEN 50000 AND 99999 THEN N'средний' ELSE N'малый' -- → ELSE снимает тихий NULL на забытом варианте END AS check_class FROM dbo.Orders AS o ) AS classified -- → поисковый CASE разметил каждый заказ; производной дан алиас GROUP BY check_class ORDER BY orders_cnt DESC;SQL
ISNULL против COALESCE
ISNULL принимает ровно два аргумента и наследует тип первого; COALESCE берёт цепочку любой длины и приводит по приоритету типов. Курс берёт COALESCE как стандартную и предсказуемую форму:
Чистый код
SELECT c.FullName,
ISNULL(c.Email, N'почта не указана') AS via_isnull,
COALESCE(c.Email, N'почта не указана') AS via_coalesce
FROM dbo.Customers AS c
WHERE c.CustomerID BETWEEN 1 AND 20;
GO
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
SELECT c.FullName, ISNULL(c.Email, N'почта не указана') AS via_isnull, -- → специфика T-SQL: два аргумента, тип результата — от первого COALESCE(c.Email, N'почта не указана') AS via_coalesce -- → стандарт SQL: первое не-NULL значение, тип — по приоритету FROM dbo.Customers AS c WHERE c.CustomerID BETWEEN 1 AND 20; GOSQL
5. Задачи и эталонные решения
Семь задач на контексте TechStore.
- описательная строка товара: название, категория в скобках, цена со знаком рубля — без NULL-обнуления;
- логин почты: подстрока адреса слева от знака эт, без догадок на единицу;
- возраст базы заказов: полных дней между самым ранним и поздним, с оговоркой про границы суток в комментарии;
- класс чека каждого заказа и число заказов в классе — поисковым CASE;
- день недели с наибольшим числом заказов — с фиксацией SET DATEFIRST;
- три грязных литерала дат через TRY_CONVERT: NULL по плохим, дата по хорошим;
- контакт клиента с заменой NULL — дважды: ISNULL и COALESCE, и письменное различие.
Эталон задачи 9.6
грязные даты без исключений
Чистый код
SELECT src.raw_value,
TRY_CONVERT(date, src.raw_value, 104) AS parsed_date
FROM (VALUES (N'05.06.2026'), (N'2026-06-05'), (N'пятое июня'))
AS src(raw_value);
GO
- Построчный разбор
Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.
SELECT src.raw_value, TRY_CONVERT(date, src.raw_value, 104) AS parsed_date -- → стиль 104, «ДД.ММ.ГГГГ»: две первые строки распознаются FROM (VALUES (N'05.06.2026'), (N'2026-06-05'), (N'пятое июня')) -- → трёхстрочный учебный набор данных без таблицы AS src(raw_value); -- → третья строка даст NULL, а не падение пакета GOTRY_CONVERT возвращает NULL вместо падения
6. Типичные ошибки урока
- Склейка плюсом с NULL — строка обнуляется на части данных; CONCAT или COALESCE лечат.
- DATEDIFF прочитан как длительность — границы, а не сутки; для полных суток считают часы и минуты.
- Мигрень DATEFIRST — номер дня недели плавает между средами; пакет фиксируется SET DATEFIRST.
- FORMAT в большом отчёте — заметное замедление; форматирует клиентское приложение, сервер отдаёт сырое.
- CASE без ELSE — тихий NULL на забытом варианте.
- TRY_CONVERT всюду — маскирует грязь навсегда; его место — импорт и первичная диагностика, а не обиходные отчёты.
7. Чек-лист практики и источники
Чек-лист урока 9
отметки делаются по факту
Источники для углубления:
- Функции дат и времени: полный список;
- CASE: простая и поисковая формы;
- TRY_CONVERT: преобразования без падения.
Проверено: 23.10.2026
↑ К оглавлению