Второй раз сталкиваюсь с неспортивным поведением со стороны MSSQL. И дабы встретив третий не тратить на него полдня документирую.
Имеется:
- два слинкованных MSSQL-сервера
- подключение к одному из них
- хранимая процедура на другом
Требуется:
- вызвать эту процедуру c набором параметров и получить результат.
Решение:
exec LINKED_SERVER.SELECTED_DATABASE.dbo.procedure_name @param_2=value, @param_1=value, @param_3=value…
Ничего не предвещает беды. Небо чистое, коннект уверенный, лаг умеренный… и тут… растёт напряжение, давит тишина, в жилах стынет кровь и появляется леденящий душу ПИЗДЕЦ!
Я не случайно параметры написал “вразнобой”. Казалось бы ничего криминального – они же именованы. И всё отлично покуда все параметры принимают какие-либо значения. Но как только окажется что @param_2=null (или @param_1) вы будете приятно удивлены загадочными сообщениями вроде “а почему это параметр_2 не передан?” или “зачем параметр_1 ты передал мне два раза?”. И будете долго биться в истерике, когда окажется, что выполняя запрос сразу на нужном сервере, вы получаете нормальный результат без каких-либо сообщений об ошибках. Мистика?
Как удалось выяснить – параметр, который null на линкованный сервер попадает уже без имени (т.е. не “@param_2=null, @param_1=value, @param_2=value”, a “NULL, @param_1=value, @param_3=value” и как следствие – этот самый NULL в данном случае будет считаться первым входным параметром в процедуре…
Решение было тривиальным(и глупым) – вынести все параметры, которые могут быть null, в конец объявления. Но если кто-то объяснит суть описываемого явления, и красивый выход из такого положения – буду очень признателен.
Не знаю конкретно как в MSSQL, но вообще в SQL принято работать с NULL как
param_2 IS NULL, а выражение типа param_2=null даст неопределенность независимо от значения param_2