Pull to refresh

Comments 9

Простите, но тут проблема не в удалении и создании таблиц, а в неправильном использовании процедур Alpha и Beta. Редактор совершенно верно указал, где ошибка.

Ее там нет. Вполне допустимо писать процедуру, которая использует временную таблицу, созданную вне ее. У этого есть небольшие последствия в виде перекопиляций, но криминала нет.

Этот "антипатерн" растёт оттуда же - если надо код из хранимки выполнить отдельно

Мне обидно, что SQL server считают идиотом со стекающими от вырождения слюнями, идиотом, неспособным заботиться о контексте выполнения

Ваш код способен сделать из разработчика, который читает ваш код, - такого идиота. Он очень удивится, что в начале и конце хранимки у таблицы поля разные

Таблицы по завершении сессии сами удалятся, так? Как-то даже в голову не приходило дропать их. А что с ##-таблицами происходит? Когда они чистятся?

Да, удаляются сами. А ## таблицы глобальны, надо удалять ручками, и можно использовать для передачи данных между коннекциями

Да, ещё забыл написать: уровень контекста образует не только процедура, но и exec(string)

Дополню свои прошлые сообщения тут таким примером.

И да, я реально считаю MSSQL тупым идиотом. Но я знаю как с этим бороться.

create or alter procedure up_second
as
begin
  create table #t (
      inc int not null identity(1,1)
    , value_i int not null
    , primary key (inc)
  )

  insert into #t (value_i)
  select 2

  select 'DEBUG 2' [DEBUG 2], * from #t

end
GO

create or alter procedure up_main
as
begin
  create table #t (
      inc int not null identity(1,1)
    , value_s varchar(max) not null
    , primary key (inc)
  )
  insert into #t (value_s)
  select 's1'


  select 'DEBUG 1' [DEBUG 1], * from #t

  exec up_second

  select 'DEBUG 3' [DEBUG 3], * from #t

end
GO

--exec up_second
exec up_main
GO

drop procedure up_main
drop procedure up_second

Вот пример кода. Мы ожидаем тут увидеть Во втором отладочном селекте value_i = 2

Но этого не произойдёт, потому что мы на самом деле получим ошибку

Msg 207, Level 16, State 1, Procedure up_second, Line 10 [Batch Start Line 37]
Invalid column name 'value_i'.

Дропнуть таблицу в начале - тоже не приведёт ни к чему хорошему.

Дальше - интереснее. Если добавить вызов up_second перед up_main - то все работает и не падает и каждая из процедур нормально воспринимает свой контекст. Потому что в этому случае сервер компилирует up_second на использование таблицы с интовым полем.

И вывод из всего этого нужно сделать такой:

1) Конструкции когда дропаются в начале хранимки временные таблицы - они допустимы

Но надо быть уверенным, что это "головная" хранимка. Во внутренних - это действительно может быть проблемой

if object_id('tempdb..#mytemp') is not null
DROP TABLE #mytemp

или

DROP TABLE if exists #mytemp

2) Внутренние хранимки не должны сами создавать таблицы, если ожидают данные из какой-то известной внешней временной таблицы

И при разработке таких хранимок нужно помнить, какую структуру имеет таблица

Странно что список колонок в insert так влияет. Без него все ok

Часто такие дропы нужны в скриптах, пока идет активная разработка: добавил поле - словил ошибку выполнения, так как времянка в контексте еще хранит старый состав. А если всунул дроп в начало - то всё ок.

Другое дело, что после того как скрипт доделан и оборачивается уже в хранимку/функцию, часто лишний код не чистится..)

Sign up to leave a comment.

Articles