Adding extended properties to all stored procs - sql-server

We're trying to add versioning to a ms sql database. Since the database has now been deployed to over 400 branches and with the clients insistence in staggered rollouts it has become very difficult to manage which branches have which db fixes.
I've proposed we add a release_version extended property to all the stored procs in the databases and use that to help with the management. After scanning the web I've come up with the following script but can't seem to get it working right; can anybody assist in getting the script right?
SELECT 'EXEC sys.sp_addextendedproperty
#name = N''Release_Version'',
#value = N''1.0.0'',
#level0type = N''SCHEMA'',
#level0name = [' + ROUTINE_SCHEMA + '],
#level1type = N''PROCEDURE'',
#level1name = [' + ROUTINE_NAME + '];'
FROM information_schema.routines where ROUTINE_TYPE = 'PROCEDURE' ORDER BY ROUTINE_NAME
When I execute this I get a resultset of the correct execution statements but how do I actually execute them?
EXEC sys.sp_addextendedproperty #name = N'Release_Version', #value = N'1.0.0', #level0type = N'SCHEMA', #level0name = [dbo], #level1type = N'PROCEDURE', #level1name = [sp_AlterTicketHistoryTable];
EXEC sys.sp_addextendedproperty #name = N'Release_Version', #value = N'1.0.0', #level0type = N'SCHEMA', #level0name = [dbo], #level1type = N'PROCEDURE', #level1name = [sp_AlterTicketTransTable];
EXEC sys.sp_addextendedproperty #name = N'Release_Version', #value = N'1.0.0', #level0type = N'SCHEMA', #level0name = [dbo], #level1type = N'PROCEDURE', #level1name = [sp_BackupAcknowledgementHistory];
...
[NOTE]: My mistake ... I was under the impression that the statements would execute automatically, instead I need to loop through and specifically execute.

Related

How to create the date wise backup file using T-SQL script

I wrote the following script but it shows an error due to the + sign in #command argument. Could anyone suggest how I can get rid of this error?
USE msdb;
GO
--add a job
EXEC dbo.sp_add_job
#job_name = N'FullBackup';
GO
USE msdb;
GO
--add jobsteps to jobsteps
DECLARE #fileName VARCHAR(90);
DECLARE #db_name VARCHAR(20);
DECLARE #fileDate VARCHAR(20);
DECLARE #commandtxt VARCHAR(100);
SET #fileName = 'D:\SQL server\BackUp\';
--SET #db_name = 'AdventureWorks_';
SET #fileDate = CONVERT(VARCHAR(8), GETDATE(),112);
SET #fileName = #fileName + #db_name + RTRIM(#fileDate) + '.bak';
SET #commandtxt = N'''BACKUP DATABASE [AdventureWorks2012] TO DISK =N''' + #fileName + ''' WITH INIT';
EXEC sp_add_jobstep
#job_name = N'FullBackup',
#step_name = N'Weekly Full Backup',
#subsystem = N'TSQL',
#command = 'BACKUP DATABASE [AdventureWorks2012] TO DISK =N''' + #fileName + ''' WITH INIT',
#retry_attempts = 5,
#retry_interval = 5;
GO
--Create a Schedule for this job, backup, occurs once a week each friday at 11:59
EXEC sp_add_schedule
#schedule_name = N'WeeklyBackup1',
#freq_type = 8,
#freq_interval = 32,
#freq_recurrence_factor = 1,
#active_start_time = 235900;
GO
--attach the schedule to the job
EXEC sp_attach_schedule
#job_name = N'FullBackup',
#schedule_name = N'WeeklyBackup1';
GO
EXEC dbo.sp_add_jobserver
#job_name = N'FullBackup';
GO
Try this
SET #commandtxt = N'BACKUP DATABASE [AdventureWorks2012] TO DISK =N''' + #fileName + ''' WITH INIT'
EXEC sp_add_jobstep
#job_name = N'FullBackup',
#step_name = N'Weekly Full Backup',
#subsystem = N'TSQL',
#command = #Commandtxt,
#retry_attempts = 5,
#retry_interval = 5;
GO
.
.
.

How to retrieve a part of a stored procedure's header?

I have a C# WinForms application that manages stored procedures used by different services. What the users see is something like that:
exec stored_procedure_name param1, param2, param3
And since param1 doesn't mean anything to them (they can't see the stored procedure), I would like to present to them small descriptions of the parameters which are normally saved in the header of the stored procedure.
A typical stored procedure would like:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[stored_procedure_name]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[stored_procedure_name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*************************************************************************************
[Procedure Info]
Author = myName
Description = this stored procedure returns results.
**************************************************************************************
[Parameters Info]
#param1 = this is parameter one
#param2 = this is parameter two
#param3 = this is parameter three
**************************************************************************************
[Changes]
2015-06-17 The stored procedure is optimized.
*/
CREATE PROCEDURE [dbo].[stored_procedure_name]
#param1 int,
#param2 nvarchar(20),
#param3 nvarchar(10)
AS
BEGIN
-- SP code here
END
GO
From the above, I want to get the descriptions in the Parameters info. I know that I can use the following SQL to retrieve the stored procedure as text/table:
CREATE TABLE #tmpHeader
(
TEXT NVARCHAR(1000)
)
INSERT INTO #tmpHeader
EXEC sp_helptext 'stored_procedure_name';
SELECT * FROM #tmpHeader
DROP TABLE #tmpHeader
Any ideas or suggestions how to proceed from here in order to get the content of the parameters info?
I am also open to any other suggestions.
Consider using extended properties to store meta-data. This is much cleaner than parsing the module text.
EDIT:
The example below returns all parameters plus descriptions for those parameters with extended properties. In your code, you can pass the schema and object names as parameters instead of the local variables used here for illustration.
EXEC sp_addextendedproperty #name = N'Description',
#value = 'this is parameter one', #level0type = N'Schema',
#level0name = 'dbo', #level1type = N'Procedure',
#level1name = 'stored_procedure_name', #level2type = N'Parameter',
#level2name = '#param1';
GO
EXEC sp_addextendedproperty #name = N'Description',
#value = 'this is parameter two', #level0type = N'Schema',
#level0name = 'dbo', #level1type = N'Procedure',
#level1name = 'stored_procedure_name', #level2type = N'Parameter',
#level2name = '#param2';
GO
EXEC sp_addextendedproperty #name = N'Description',
#value = 'this is parameter three', #level0type = N'Schema',
#level0name = 'dbo', #level1type = N'Procedure',
#level1name = 'stored_procedure_name', #level2type = N'Parameter',
#level2name = '#param3';
GO
DECLARE
#SchemaName sysname = 'dbo'
, #ObjectName sysname = 'stored_procedure_name';
SELECT properties.objtype
, properties.objname
, parms.name
, properties.value
FROM sys.parameters AS parms
LEFT JOIN fn_listextendedproperty('Description', 'Schema', #SchemaName, 'Procedure',
#ObjectName, 'Parameter', DEFAULT) AS properties ON
properties.objname COLLATE DATABASE_DEFAULT = parms.name
WHERE
parms.object_id = OBJECT_ID(QUOTENAME(#SchemaName) + '.' + QUOTENAME(#ObjectName));
GO
This should make the think your looking for.
SELECT SUBSTRING(definition,CHARINDEX(N'[Parameters Info]',definition),CHARINDEX(N'[',definition,CHARINDEX(N'[Parameters Info]',definition)+1)-CHARINDEX(N'[Parameters Info]',definition))
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('YOUR PROCEDURE!!!')
It searches for Parameters Info and goes any further until if finds another header block (beginning with [). You can also specify that it should search for *.

How to update Extended Properties of a Column?

The questions really says it all, Is it possible to update an extended property of a column in a table. I have been looking around online but they only seem to show updating the extended property for a table and not the columns in a table.
EXECUTE sp_updateextendedproperty
N'MS_Description',
#v,
N'SCHEMA', N'dbo',
N'TABLE', N'Table_1',
N'COLUMN', N'i'
It's actually the very first sample in MSDN topic:
http://technet.microsoft.com/en-us/library/ms186885.aspx
Here's a more complete sample:
--Add extended property
EXEC sp_addextendedproperty
#name = N'Question1'
,#value = N'Hello'
,#level0type = N'Schema', #level0name = dbo
,#level1type = N'Table', #level1name = Acceptance
,#level2type = N'Column', #level2name = P101;
GO
--Verify
SELECT * FROM fn_listextendedproperty
(NULL, 'schema', 'dbo', 'table', 'Acceptance', 'column', 'P101');
GO
--Update the extended property.
EXEC sp_updateextendedproperty
#name = N'Question1'
,#value = N'Hello, What is your name'
,#level0type = N'Schema', #level0name = dbo
,#level1type = N'Table', #level1name = Acceptance
,#level2type = N'Column', #level2name = P101;
GO
--Verify
SELECT * FROM fn_listextendedproperty
(NULL, 'schema', 'dbo', 'table', 'Acceptance', 'column', 'P101');
GO

transactional replication using script

I am able to configure transactional replication using SSMS and it works properly. But i want to configure it using script so that i use it from my c#/vb application.
Is there any way to do that?
If you complete all the step of transactional replication using SSMS then it's not complicated to do with the script.
Just carefully observe that when you configure distribution, publication and subscription SSMS gives you the option to generate script in every step.
You can use that generated script.
But only difference is when you add articles to publication. You can use the following code to add article
declare #name nvarchar(50)
declare curname cursor for
select name from sysobjects where type = 'U'
open curname
fetch next from curname into #name
while ##FETCH_STATUS = 0
begin
if exists(select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = #name AND TABLE_SCHEMA = 'dbo')
begin
exec sp_addarticle
#publication = N'publication_name', #article = #name, #source_owner = N'dbo',
#source_object = #name, #type = N'logbased', #description = null, #creation_script = null,
#pre_creation_cmd = N'drop', #schema_option = 0x000000000803509F,
#identityrangemanagementoption = N'manual', #destination_table = #name,
#destination_owner = N'dbo', #vertical_partition = N''
end
fetch next from curname into #name
end
close curname
deallocate curname
Or, you can see https://hasibarnab.wordpress.com/category/sql-server/replication/
DECLARE #returncode int
EXEC #returncode = xp_cmdshell 'dtexec /f "C:\thePackage.dtsx"'
Check out sp_addpublication, sp_addarticle, and sp_addsubscription in BOL.

Wrapper stored procedure to create publication for transactional replication

I have created a wrapper stored procedure to create publication for transactional replication for SQL Server 2008 Standard Edition SP3. But when I execute the procedure I get the following error. The column "file_exists" is not user defined. This error doesn't make any sense to me. This works on Dev environment but same code doesn't work on test environment. Dev and Test are identical as far as I can tell. I also tried to explicitly set options, made them 5496 (SELECT ##OPTIONS). Any help greatly appreciated.
-- error
Msg 50000, Level 16, State 1, Procedure CreatePublicationForDB, Line 161
Invalid column name 'file_exists'.
-- Begin Script
CREATE DATABASE TestPublication
GO
USE TestPublication
CREATE TABLE Orders(
OrderID INT PRIMARY KEY,
CustomerID INT,
ProductID INT,
UpdatedAt DATETIME,
UpdatedBy DATETIME
)
GO
CREATE TABLE Products(
ProductID INT PRIMARY KEY,
ProductName VARCHAR(100)
)
GO
CREATE VIEW V_Order
AS
SELECT o.OrderID,o.CustomerID, p.ProductName
FROM Orders o
JOIN Products p
ON o.ProductID = p.ProductID
GO
CREATE SCHEMA repl
GO
CREATE TABLE repl.ReplicationTables
(
DBName sys.sysname NOT NULL DEFAULT('TestPublication'),
SchemaOwner sys.sysname NOT NULL DEFAULT('dbo'),
TableName sys.sysname NOT NULL
)
GO
INSERT INTO repl.ReplicationTables (tablename)
VALUES('Orders'),('Products'),('V_Order')
GO
USE TestPublication
GO
CREATE PROCEDURE CreatePublicationForDB( #databaseName sysname, #publicationName sysname = #databaseName, #allow_initialize_from_backup NVARCHAR(5) = 'true')
AS
BEGIN
BEGIN TRY
SET ANSI_WARNINGS ON
SET ANSI_PADDING ON
SET ANSI_NULLS ON
SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULL_DFLT_ON ON
SET CONCAT_NULL_YIELDS_NULL ON
DECLARE #sp_replicationdboption varchar(MAX) = ' USE '+#databaseName +';',
#sp_addpulication VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_addpublication_snapshot VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_addarticle VARCHAR(MAX) = ' USE '+#databaseName +';',
#sp_startpublication_snapshot VARCHAR(MAX) = ' USE '+#databaseName +';'
DECLARE #allow_anonymous NVARCHAR(5) = CASE WHEN #allow_initialize_from_backup = 'false' OR #allow_initialize_from_backup IS NULL THEN 'true' ELSE 'false' END
DECLARE #immediate_sync NVARCHAR(5) = #allow_anonymous, #publisher sysname = ##SERVERNAME
-- set up database publication
SET #sp_replicationdboption += '
exec sp_replicationdboption #dbname = N'''+#databaseName+ ''',
#optname = N''publish'',
#value = N''true'''
-- Publication
SET #sp_addpulication += '
exec sp_addpublication #publication = N'''+#publicationName+ ''',
#description = N''Transactional publication of database '+#databaseName+' from Publisher '+#publisher+''',
#sync_method = N''concurrent'',
#retention = 0,
#allow_push = N''true'',
#allow_pull = N''true'',
#allow_anonymous = N'''+#allow_anonymous+ ''' ,
#enabled_for_internet = N''false'',
#snapshot_in_defaultfolder = N''true'',
#compress_snapshot = N''false'',
#ftp_port = 21,
#ftp_login = N''anonymous'',
#allow_subscription_copy = N''false'',
#add_to_active_directory = N''false'',
#repl_freq = N''continuous'',
#status = N''active'',
#independent_agent = N''true'',
#immediate_sync = N'''+#immediate_sync+ ''' ,
#allow_sync_tran = N''false'',
#autogen_sync_procs = N''false'',
#allow_queued_tran = N''false'',
#allow_dts = N''false'',
#replicate_ddl = 1,
#allow_initialize_from_backup = N'''+COALESCE(#allow_initialize_from_backup, 'false')+ ''' ,
#enabled_for_p2p = N''false'',
#enabled_for_het_sub = N''false'''
IF #allow_initialize_from_backup = 'false'
BEGIN
-- publication snapshot
SET #sp_addpublication_snapshot +='
exec sp_addpublication_snapshot #publication = N'''+#publicationName+ ''',
#frequency_type = 1,
#frequency_interval = 0,
#frequency_relative_interval = 0,
#frequency_recurrence_factor = 0,
#frequency_subday = 0,
#frequency_subday_interval = 0,
#active_start_time_of_day = 0,
#active_end_time_of_day = 235959,
#active_start_date = 0,
#active_end_date = 0,
#job_login = null,
#job_password = null,
#publisher_security_mode = 1'
SET #sp_startpublication_snapshot+=' exec sys.sp_startpublication_snapshot #publication = N'''+#publicationName+ ''''
END
-- Articles
IF OBJECT_ID('tempdb..#t') IS NULL
BEGIN
PRINT 'creating temp table t'
CREATE TABLE #t (NAME sysname,objectid INT, sch_owner sysname NULL, article sysname NOT NULL, isIndexed BIT NULL, IsSchemaBound BIT NULL, TYPE CHAR(2) NULL)
END
INSERT INTO #t(NAME,objectid, sch_owner,isIndexed,IsSchemaBound, TYPE,article)
EXEC('
USE '+#databaseName + '
SELECT f.Name, f.object_id,f.sch, f.IsIndexed,f.IsSchemaBound, f.type,CASE WHEN ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) > 1 THEN f.name + CAST((ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) - 1) AS VARCHAR(2)) ELSE f.name END AS Article
FROM(
SELECT t.Name, t.object_id,t.sch, IsIndexed,IsSchemaBound, type
FROM
(SELECT DBName, SchemaOwner, TableName
FROM TestPublication.repl.ReplicationTables
GROUP BY DBName, SchemaOwner, TableName )rt JOIN
(SELECT o.Name, o.object_id,s.name AS sch, objectproperty(o.object_id, ''IsIndexed'') AS IsIndexed,objectproperty(o.object_id, ''IsSchemaBound'') AS IsSchemaBound, o.type
FROM
sys.objects o
JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.type IN (''U'',''V'')
AND ObjectProperty(o.object_id, ''IsMSShipped'') = 0
AND (ObjectProperty(o.object_id, ''TableHasPrimaryKey'') = 1 OR ObjectProperty(o.object_id, ''TableHasPrimaryKey'') IS NULL)
) t ON rt.tablename = t.name AND rt.SchemaOwner = t.sch
WHERE rt.DBName = '''+#databaseName + '''
) f'
)
SELECT #sp_addarticle +=
'exec sp_addarticle
#publication = N''' +#databaseName +
''', #article = N''' +t.article+
''', #source_owner = N''' +t.sch_owner +
''', #source_object = N''' + t.NAME +
''', #type = N''' +
CASE WHEN t.type = 'U' THEN 'logbased'
WHEN t.type = 'V' AND (IsIndexed = 1 OR IsSchemaBound = 1 )THEN 'indexed view schema only'
WHEN t.type = 'V' AND IsIndexed = 0 THEN 'view schema only' END
+''', #description = null,#creation_script = null,#pre_creation_cmd = N''drop'',
#schema_option = '+
CASE WHEN t.type = 'U' THEN '0x000000000803509F'
WHEN t.type = 'V' THEN '0x0000000008000001' END+
',#destination_table = N'''+t.Name+
''',#destination_owner = N'''+t.sch_owner+''''+
CASE WHEN t.TYPE = 'U' THEN
', #identityrangemanagementoption = N''manual'',#vertical_partition = N''false'',
#ins_cmd = N''CALL sp_MSins_'+t.sch_owner+''+t.Name+
''', #del_cmd = N''CALL sp_MSdel_'+t.sch_owner+''+t.Name+''',
#upd_cmd = N''SCALL sp_MSupd_'+t.sch_owner+''+t.Name+''''
ELSE ''
END
+';'
FROM #t t
PRINT 'Now running sp_replicationdboption'
PRINT #sp_replicationdboption
EXEC(#sp_replicationdboption)
PRINT 'Now running sp_addpulication'
PRINT #sp_addpulication
EXEC(#sp_addpulication)
IF #allow_initialize_from_backup = 'false'
BEGIN
PRINT 'Now running sp_addpulication_snapshot and starting snapshot'
PRINT #sp_addpublication_snapshot
EXEC(#sp_addpublication_snapshot)
EXEC(#sp_startpublication_snapshot)
END
PRINT 'Now running sp_addarticles'
PRINT #sp_addarticle
EXEC(#sp_addarticle)
-- exec sp_droppublication #publication = N'Products'
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK
DECLARE #ERROR_SEVERITY INT, #ERROR_STATE INT, #ERROR_MESSAGE NVARCHAR(4000)
SELECT #ERROR_SEVERITY = ERROR_SEVERITY(), #ERROR_STATE = ERROR_STATE(), #ERROR_MESSAGE = ERROR_MESSAGE()
RAISERROR(#ERROR_MESSAGE, #ERROR_SEVERITY, #ERROR_STATE)
END CATCH
END
GO
and finally execute
EXEC CreatePublicationForDB 'TestPublication'
-- drop replication in case you want to run the above again.
exec TestPublication.dbo.sp_droppublication #publication = 'TestPublication'
exec TestPublication.dbo.sp_replicationdboption #dbname = 'TestPublication', #optname = 'publish', #value = 'false'
-- cleanup database
DROP DATABASE TestPublication
Sorry, old post I know, but I ran into a very similar situation and got around it. I haven't found a workable solution anywhere else. I'm including my experience to help others.
Summary of my situation is that I have an msbuild process running a series of scripts from a manifest file (text file with a series of script names) within a transaction. The scripts that were intended to create and configure agent jobs always died with the same error. (invalid column name "file_exists")
Procs used in my failing script(s):
msdb.dbo.sp_add_category
msdb.dbo.sp_add_job
msdb.dbo.sp_add_jobstep
msdb.dbo.sp_update_job
msdb.dbo.sp_add_jobschedule
msdb.dbo.sp_add_jobserver
Commenting out the call to msdb.dbo.sp_add_jobstep allowed the script to complete.
I do have SQL command variables in the form #database_name=N'$(DatabaseName)' in the script as well. This led to some misdirected efforts to try to use escape macros as mentioned in the "Important" note under [ #command= ] 'command' on the documentation for sp_add_jobstep.
https://msdn.microsoft.com/en-us/library/ms187358.aspx
If I run the build up to, but not including, the job creation script and start over, it succeeds.
What I found, after much trial and error, was that, even though the procs are qualified as being in [MSDB], unless I actually included a USE statement, the process fails. By beginning the script with "USE [MSDB] GO" and then switching back to my build target (i.e. USE [MyBuildDB] GO), I no longer get the error.
My agent jobs create as expected, and several scripts within the build run without error.
It's hard to say what the problem is without seeing all of the code and having the schema. I'd recommend not creating a wrapper to create publication(s). The create publication scripts can be saved and executed on demand when needed - eliminating the need for a wrapper.

Resources