Для тех, кто не знает, SNAFU — персонаж военных патриотических мультфильмов, созданных американцами во время войны. Этот раздолбай, ввиду природного идиотизма, все время попадает в катастрофические ситуации и, как правило, гибнет в конце серии. Правда, в следующей серии он снова оказывается живым — в этом смысле, его можно считать далеким прародителем Кенни из Южного Парка.

При наборе людей на позицию SQL server developer, я часто был покорен тем, как они отвечали на вопросы. Я готов был сказать им ДА, если бы меня не спасала небольшая задача в одну строчку, которую предложил мой коллега. Удивительно, сколько всего может дать эта задача в одну строку SQL. И вот уже кандидат уже с упоением ходит по граблям. А грабель, как вы увидите, там много. Конечно, ни один человек не собрал ВСЕ возможные грабли. Но, чтобы их все показать, мне и понадобился SNAFU.

Итак, задача:

SELECT * FROM Events where DT='2020/02/03'

  • Что хотел сделать автор кода?
  • Почему это может работать не так, как хотелось?
  • Как это исправить?

Дальше пойдет мой разговор со SNAFU.

SNAFU: Очевидно, запрос выбирает данные за один день.
Я: А что здесь плохого?
SNAFU: Ну, там звездочка, лучше бы указать поля…
Я: А что хранится в таблице, как думаете? И какого типа поле DT?
SNAFU: События… Время событий… Значит datetime
Я: Ну и?
SNAFU: (после раздумий) ааа, так если там время, то прочитается записи только за полночь
Я: отлично

Мы одолели первые два пункта и переходим к третьему.

Я: Как это исправить?
SNAFU: where convert(varchar,DT,102)='2020/02/03' (Грабли #1 сработали)
Я: А вас не смущает, что это может помешать SQL использовать индекс по DT, если он там есть?
SNAFU: where DT between '2020/02/03' and '2020/02/04' (Грабли #2 сработали)
Я: А вас не смущает, что сюда войдут еще и данные за следующее число (полночь)?
SNAFU: where DT between '2020/02/03' and '2020/02/03 23:59:59' (Грабли #3 сработали)
Я: А вам бы понравилось иметь дело с банком, в котором есть секунда, когда деньги, которые вы внесли, будут потеряны?
SNAFU: where DT between '2020/02/03' and '2020/02/03 23:59:59.999' (Грабли #4 сработали)
Я: А вы в курсе, что 23:59:59.999 будет снова округлено до полуночи?
SNAFU: Точно, там гранулярность 13-16ms. Тогда: where DT between '2020/02/03' and '2020/02/03 23:59:59.986' (Грабли #5 сработали)
Я: То есть если DT станет smalldatetime или datetime2, все перестанет работать?



Я не знаю, почему переход к моменту ниже такой сложный. Реально, более половины кандидатов тупят отчаянно. Иногда приходится подсказывать. Но наш SNAFU вымучил решение:

SNAFU: where DT>='2020/02/03' and DT<'2020/02/04'
Я: Наконец то.

SNAFU вытирает пот со лба. Теперь самое время для контролького выстрела.
Я: А что ЕЩЕ здесь совсем плохо?
SNAFU трясет. Его руки дрожат. Взгляд блуждает.
Я: Это 3 февраля или 2 марта?

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