Подводные камни при работе в "1С:Підприємство" c датами
Работа с датой
Знал бы, где упасть – соломки бы подстелил
(Народная мудрость)
Довелось
в практической деятельности разработчика в "1С:Підприємство" столкнуться со следующим
явлением. В базе было создано наперед несколько тысяч объектов
справочника «Информационные карты» - для последующего занесения в них и
хранения информации о постоянных покупателях торговой сети. Объектов
было создано примерно 10 тысяч, на момент возникновения инцидента
заполнено данными было около 7 тысяч карт. Каждое утро одно регламентное
задание находило именинников среди клиентов сети (данные о которых были
занесены в базу), а другое рассылало им поздравительные СМС с
приглашениями получить подарок в любом удобном покупателю магазине.
Запрос, который выбирал именинников из общей массы, имел приблизительно
следующий вид:ЗапросИменинников = Новый Запрос; ЗапросИменинников.Текст = “Выбрать | ИнформационныеКарты.Ссылка | ГДЕ | День(ИнформационныеКарты.ДатаРожденияКлиента) = &День | И Месяц(ИнформационныеКарты.ДатаРожденияКлиента) = &Месяц”;На место параметров «День» и «Месяц» подставлялись соответствующие день и месяц текущего дня. Всё шло своим чередом, именинников в среднем находилось по 10-20 с периодическими всплесками до 30, но тут наступило 1е января. Регламент вдруг посчитал нужным поздравить почти 3 тысячи человек (к счастью, телефоны были указаны только у 300 из этого количества).
Анализ ситуации показал, что причиной такого поведения процедуры стало своеобразное понимание понятия NULL создателями среды "1С:Підприємство" (а также нежелание привести это понимание к общему знаменателю с пониманием этого у авторов языка запросов SQL).
В данном конкретном случае дело было в следующем. Даже незаполненное данными поле типа ДАТА вовсе не равно NULL, как можно было бы подумать. Среда "1С:Підприємство" в пустое поле ДАТА записывает значение Дата(“00010101”), то есть 1 января 0001-го года (видимо, нашей эры, хотя я не был бы столь уверен – имея опыт работы с "1С:Підприємство" больше недели), при этом никак не отражая это на форме. В то же время – хотя какие-то данные в поле (и соответствующую ячейку памяти) записаны, функция ЗначениеЗаполнено(Дата) возвращает Ложь. Это обстоятельство стоит учитывать при разработке операций с датами (хотя тип ДАТА вовсе не единственный, где NULLи не заполненное значение вовсе не тождественны) – во избежание подобных затруднений.
Конкретно в данном случае можно либо при обработке результатов запроса проверять значение ДатаРожденияКлиента на заполненность (что менее производительно), либо задавать в запросе отбор еще и по году рождения клиента (например с 1800 – чтобы наверняка)
ЗапросИменинников = Новый Запрос; ЗапросИменинников.Текст = “Выбрать | ИнформационныеКарты.Ссылка | ГДЕ | День(ИнформационныеКарты.ДатаРожденияКлиента) = &День | И Месяц(ИнформационныеКарты.ДатаРожденияКлиента) = &Месяц | И Год(ИнформационныеКарты.ДатаРожденияКлиента) > 1800”;
Автор: Виталий Моргун
Комментарии