Перейти к содержимому

Функции и выражения: строки, даты, 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знаки без правых пробелов и байтыне путать их
Склейка плюсом: оператор плюс при NULL в любом слагаемом по умолчанию даёт NULL всей строки: описательная колонка молча пустеет на части данных. В курсе склейка идёт через CONCAT.

Чистый код

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;
SQL
  • Построчный разбор

    Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.

    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)чистая дата без временидля календарных срезов
Границы вместо длительности: DATEDIFF(day, 23:59, 00:01) равен единице: функция считает пересечённые границы суток, а не прошедшие двадцать четыре часа. Для «полных часов и дней» считают минуты и часы с делением.
Локаль недели: номер дня недели от DATEPART(weekday) плывёт между серверами с разным SET DATEFIRST; в боевых отчётах пакет начинается с явной фиксации: SET DATEFIRST 1.
↑ К оглавлению

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;
SQL
  • Построчный разбор

    Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.

    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
SQL
  • Построчный разбор

    Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.

    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;
    GO
    SQL
ELSE забывание: CASE без ELSE возвращает NULL на пропущенные варианты: либо ELSE пишется явно, либо намеренный NULL комментируется.
↑ К оглавлению

5. Задачи и эталонные решения

Семь задач на контексте TechStore.

  1. описательная строка товара: название, категория в скобках, цена со знаком рубля — без NULL-обнуления;
  2. логин почты: подстрока адреса слева от знака эт, без догадок на единицу;
  3. возраст базы заказов: полных дней между самым ранним и поздним, с оговоркой про границы суток в комментарии;
  4. класс чека каждого заказа и число заказов в классе — поисковым CASE;
  5. день недели с наибольшим числом заказов — с фиксацией SET DATEFIRST;
  6. три грязных литерала дат через TRY_CONVERT: NULL по плохим, дата по хорошим;
  7. контакт клиента с заменой 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
TRY_CONVERT возвращает NULL вместо падения
  • Построчный разбор

    Ниже приведён тот же фрагмент с пояснением после каждой смысловой строки. Строки, которые начинаются с двух дефисов и стрелки вправо, содержат комментарий преподавателя. Эти строки не являются обязательной частью программы.

    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, а не падение пакета
    GO
    TRY_CONVERT возвращает NULL вместо падения
↑ К оглавлению

6. Типичные ошибки урока

  1. Склейка плюсом с NULL — строка обнуляется на части данных; CONCAT или COALESCE лечат.
  2. DATEDIFF прочитан как длительность — границы, а не сутки; для полных суток считают часы и минуты.
  3. Мигрень DATEFIRST — номер дня недели плавает между средами; пакет фиксируется SET DATEFIRST.
  4. FORMAT в большом отчёте — заметное замедление; форматирует клиентское приложение, сервер отдаёт сырое.
  5. CASE без ELSE — тихий NULL на забытом варианте.
  6. TRY_CONVERT всюду — маскирует грязь навсегда; его место — импорт и первичная диагностика, а не обиходные отчёты.
↑ К оглавлению

7. Чек-лист практики и источники

Чек-лист урока 9

отметки делаются по факту

Источники для углубления:

  1. Функции дат и времени: полный список;
  2. CASE: простая и поисковая формы;
  3. TRY_CONVERT: преобразования без падения.
Итог: вычисляемые колонки отчётного качества пишутся без капризов типов. Урок 10 даёт способ сохранить сложный запрос под именем: представления, первые CTE и временные таблицы.

Проверено: 23.10.2026

↑ К оглавлению
Конспект:
Четверг, 22 октября 2026