Знав би, де впасти, — соломки б підстелив. Народна мудрість.
У практиці розробки для «1С:Підприємство» трапився випадок, який добре показує різницю між незаповненим значенням і NULL. У довіднику «Інформаційні картки» заздалегідь створили приблизно 10 тисяч об'єктів для даних постійних покупців торговельної мережі. На момент інциденту заповненими були близько 7 тисяч карток.
Щоранку одне регламентне завдання знаходило іменинників, а інше надсилало їм SMS із привітанням і запрошенням отримати подарунок у зручному магазині. Запит мав приблизно такий вигляд:
ЗапросИменинников = Новый Запрос;
ЗапросИменинников.Текст = “Выбрать
| ИнформационныеКарты.Ссылка
| ГДЕ
| День(ИнформационныеКарты.ДатаРожденияКлиента) = &День
| И Месяц(ИнформационныеКарты.ДатаРожденияКлиента) = &Месяц”;
Параметри «День» і «Місяць» відповідали поточній даті. Зазвичай відбір знаходив 10–20 людей, іноді до 30. Але 1 січня до нього потрапило майже 3 тисячі карток. На щастя, номери телефонів були лише приблизно у 300 із них.
Чому порожня дата потрапила до вибірки
Для реквізиту типу «Дата» значення за замовчуванням — початок відліку дат: 1 січня 0001 року. Воно не тотожне NULL. Тому перевірка лише дня й місяця знаходить і такі незаповнені дати саме 1 січня.
Функція ЗначениеЗаполнено(Дата) для значення за замовчуванням повертає Ложь. Це узгоджується з документацією платформи про незаповнені значення: NULL позначає відсутність значення в певних результатах запиту, тоді як реквізити окремих типів мають власні значення за замовчуванням.
Як виправили відбір
Можна перевіряти заповненість дати під час обробки результатів або відсіювати такі записи безпосередньо в запиті. У початковому випадку запропонували додаткову умову за роком народження:
ЗапросИменинников = Новый Запрос;
ЗапросИменинников.Текст = “Выбрать
| ИнформационныеКарты.Ссылка
| ГДЕ
| День(ИнформационныеКарты.ДатаРожденияКлиента) = &День
| И Месяц(ИнформационныеКарты.ДатаРожденияКлиента) = &Месяц
| И Год(ИнформационныеКарты.ДатаРожденияКлиента) > 1800”;
Межа 1800 тут була практичним фільтром для конкретної клієнтської бази, а не універсальним правилом роботи з датами. Вона також виключає всі дати до цієї межі. Для перевірки саме порожньої дати можна порівнювати поле зі значенням початку відліку; офіційний приклад використовує DATETIME(1, 1, 1, 0, 0, 0). Синтаксис і потрібну умову слід узгодити з мовою запиту та структурою конфігурації.
Наведені вище фрагменти збережено як початкові схематичні приклади: у них немає повного блоку джерела даних, а лапки потребують перевірки перед виконанням. Після виправлення варто перевірити відбір на 1 січня, незаповнених картках і звичайних датах народження.
Автор: Віталій Моргун.