Комментарии 14
ну и по вашей процедуре замечания:
1) Примечательно, что ее вы дропаете и создаете вместо использования аналогичного метода :)
2) Для процедуры достаточно такого определения:
EXEC('CREATE PROC [procName] AS');
3) с IF, TF нужна получше обработка. Пример: у вас уже есть инлайновая табличная функция, вы переделываете ее в мультистейтмент. Своей процедуре вы передаете TF, но при этом внутри вы должны проверить и существование IF, и существование TF, иначе вы получите ошибку либо при первом, либо при повторном запуске. альтерить IF в TF и обратно можно, но проверять нужно оба варианта
4) Вы вроде для Type и для Name забыли кавычки внутри сгенерированного кода.
5) Внутри сгенерированного кода не надо писать GO — это разделитель между батчами в студии, а не инструкция SQL.
6) Ну это мелочь — перед юникодной строкой надо ставить N.
7) Вообще непонятно, зачем вам 4 переменных, и вы выбираете, какую из них выполнить. Можно же сильно все упростить.
По итогу я бы превратил вашу процедуру в что-то такое:
IF OBJECT_ID('dbo.antidrop', 'P') IS NOT NULL
DROP PROC dbo.antidrop;
GO
CREATE PROC dbo.antidrop @name SYSNAME, @type SYSNAME
AS
BEGIN
declare @sql nvarchar(max);
select @sql = N'if ' +
case when @type in ('IF', 'TF') then N'OBJECT_ID(''' + @name + N''', ''IF'') is null and OBJECT_ID(''' + @name + N''', ''TF'') is null'
else N'OBJECT_ID(''' + @name + N''', ''' + @type + N''') IS NULL'
end + N'
EXEC(''CREATE ' +
case @type when 'IF' then N'FUNCTION'
when 'TF' then N'FUNCTION'
when 'FN' then N'FUNCTION'
when 'P' then N'PROC'
when 'V' then N'VIEW'
end +
N' ' + @name +
case @type when 'IF' then N'() RETURNS table as return (select 1 as i)'
when 'TF' then N'() RETURNS table as return (select 1 as i)'
when 'FN' then N'(@i INT) RETURNS INT AS begin return 1; end'
when 'P' then N' as'
when 'V' then N' AS SELECT 1 AS i'
end +
';'');';
exec(@sql);
END
GO
1. Исправил
2. Исправил
3. dbo.antidrop не планировалась как готовое решение, лишь пример на коленке
4. Заметил еще до модерации, но редактировать было нельзя…
5. Исправил
По поводу 4х непонятнных переменных, хотелось чтобы суть была ясна начинающим разработчикам в том числе. Безусловно были динамические мысли. В общем было принято решение оставить более простенький вариант.
А это вообще нормальная практика — менять базу на продакшене прямо под нагрузкой? Я не DBA, но почему-то считал, что у DBA есть процедуры деплоя изменений, гарантированно исключающие шаловливые ручонки на работающем продакшене.
Ваши "молитвы" услышаны https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/11/17/create-or-alter-another-great-language-enhancement-in-sql-server-2016-sp1/, начиная с 2016 SP1 работает для функций, процедур, триггеров и представлений
Ms давно (то есть недавно) в курсе, а вот потребители — увы… Я до сих пор вынужден поддержиавать sql 2000 (две тысячи ровно). И я впервые увидел эмуляцию create or alter, без дропа и без обработки ошибок на клиенте. Это так просто! Где были мои глаза?!!
Мне приходится иногда разбираться с Oracle 8 и тут уже тяжело сказать кто из них "круче".
По поводу самой техники создания болванки и ее изменения — довольно известная вещь в среде SQL Server.
Крайне рекомендую ознакомиться с отличной статьей https://habrahabr.ru/post/315142/ и просто шедевральной серией статьей Bad Habits Revival
CREATE OR ALTER
сначала тащим таблицу insert into table_new, если стащили успешно преименовываем и дропаем старую.
Соответственно, в создающем скрипте проверка на существование может быть, но только для того, чтобы он был пере-запускаемым (это удобно при активной разработке). Точно по тем же причинам, в скрипте с alter существование таблицы не стоит проверять, а вот добавляемых столбцов — может быть полезно. Естественно, в создающем скрипте раздаются права, если это требуется.
Если кто-то запустит скрипт на alter до создающего скрипта — желательно чтобы он упал, потому что, как следствие, стоит исправить что-то в процессе разработки или мыслительных процессах конкретного разработчика :)
P.S. SQL Ninja, в контексте статьи — это кто? Они под покровом ночи делают незаметные для других изменения в БД? :)
if object_id(N'SmthProc', N'p') is not null
set noexec on;
go
create procedure SmthProc
as
set nocount on;
go
set noexec off;
go
alter procedure SmthProc
as
begin
set nocount on
print N'SmthProc'
end
go
а так?
Семь раз ALTER один DROP