scheduled execution of all TSQL scripts in a folder - sql-server-2008

I have a bunch of TSQL scripts that need to be executed on a daily basis.
I know I can use Job Agent to execute them but that requires me to change the actual job.
What I would like to do is create a job that simply says:
execute all TSQL-scripts in <some folder>
A bonus would be if a filter could be used based on the filename of the script: So that one job would execute all the files whose name start with a 'd', another job would execute all those with a 'w' in the name.
Can this be done? How can this be done?
I read some things that spoke of using the Windows-scheduler to run the SQLCMD-utility.
I'd rather have the SQL Server do the scheduling and executing. Is Powershell the way to go? If so, where and how to start? (Never had to use it so never gave it much attention :/)
Thanks for thinking with me!
Henro

To execute a script from a file you can use:
DECLARE #dir varchar(100) = 'C:\MyDir\'
DECLARE #file varchar(100) = 'myScript.sql'
DECLARE #cmd varchar(100) = 'sqlcmd -S ' + ##SERVERNAME + ' -i ' + #dir + #file
EXECUTE dbo.xp_cmdshell #command_string = #cmd
To get the list of files from a dir you can use
CREATE TABLE #tbl (Name varchar(400))
DECLARE #cmd varchar(100) = 'dir ' + #dir + ' *.sql'
INSERT #tbl EXECUTE dbo.xp_cmdshell #command_string = #cmd
DELETE FROM #tbl WHERE ISDATE(SUBSTRING(Name,1,10)) = 0
UPDATE #tbl SET Name = SUBSTRING(Name, 40, 100)

I guess you can do one thing:
Put all the scripts starting with name 'd' in one sproc.Here you have to put Go after each of your scripts in sproc.
Similarly create one more sproc with all the scripts starting with letter 'w'
Then schedule these jobs in sql server agent.

João, thanks for your help. Using your code I produced this: set dateformat dmy
DECLARE #scripts varchar(100) = 'C:\MYSCRIPTS\' -- folder with scripts
DECLARE #project varchar(100) = 'PROJECTX' -- specific folder
DECLARE #Identifier varchar(1) = 'D' -- All files of which the name starts with a 'T'
DECLARE #files varchar(100) = #scripts + #project + '\' + #Identifier + '*.sql'
CREATE TABLE #tbl1 (Name varchar(400))
DECLARE #cmd varchar(100) = 'dir ' + #files
INSERT #tbl1 EXECUTE master.dbo.xp_cmdshell #command_string = #cmd
DELETE FROM #tbl1 WHERE ISDATE(SUBSTRING(Name,1,10)) = 0
UPDATE #tbl1 SET Name = SUBSTRING(Name,37, 100)
CREATE TABLE #tbl2 (Counter smallint Primary Key IDENTITY(1,1), Name varchar(400))
INSERT INTO #tbl2 (Name)
Select #scripts + #project + '\' + Name from #tbl1
DECLARE #i int
DECLARE #NumRows int
DECLARE #File2BExecuted varchar(100)
SET #i = 1
SET #NumRows = (SELECT COUNT(*) FROM #tbl2)
IF #NumRows > 0
WHILE (#i <= (SELECT MAX(Counter) FROM #tbl2))
BEGIN
SELECT #File2BExecuted = Name FROM #tbl2 WHERE Counter = #i
DECLARE #script varchar(100) = 'sqlcmd -S ' + ##SERVERNAME + ' -i ' + #File2BExecuted
EXECUTE master.dbo.xp_cmdshell #command_string = #script
SET #i = #i + 1
END
drop table #tbl1
drop table #tbl2

Related

How to have SQL Server 2008 trigger when a job is created/deleted

How to set up a SQL Server 2008 Trigger that sends an Email Alert when a Job is Created/Deleted
I have created a trigger, with the help of many hours of research. The trigger currently emails out to a recipient when a SQL job has been enabled/disabled. The trigger has been tested and works without fail.
I would like to extend the trigger out to capture the creation and deletion of jobs as well, but I am not sure how.
Here is the code that I have:
USE [msdb]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[jobChecker]
ON sysjobs
FOR UPDATE AS
SET NOCOUNT ON
-- # DECLARE VARIABLES # --
DECLARE #username VARCHAR(50),
#hostName VARCHAR(50),
#jobName VARCHAR(100),
#newEnabled INT,
#oldEnabled INT,
#jobCreated INT,
#bodyText VARCHAR(200),
#subjectText VARCHAR(200),
#servername VARCHAR(50),
#profileName VARCHAR(50) = 'profile_name',
#recipients VARCHAR(500) = 'example#domain.com'
-- # SET VARIABLES # --
SELECT #username = SYSTEM_USER
SELECT #hostName = HOST_NAME()
SELECT #servername = ##servername
SELECT #newEnabled = ENABLED FROM Inserted
SELECT #oldEnabled = ENABLED FROM Deleted
SELECT #jobName = Name FROM Inserted
-- # CHECK FOR ENABLED/DISABLED # --
IF #newEnabled <> #oldEnabled
BEGIN
IF #newEnabled = 1
BEGIN
SET #bodyText = 'The user (' + #username + ') enabled the job from ' + #hostName + ' on ' + CONVERT(VARCHAR(20),GETDATE(),100) + '.'
SET #subjectText = #servername + ' : [' + #jobName + '] has been ENABLED'
END
IF #newEnabled = 0
BEGIN
SET #bodyText = 'The user (' + #username + ') disabled the job from ' + #hostName + ' on ' + CONVERT(VARCHAR(20),GETDATE(),100) + '.'
SET #subjectText = #servername+' : [' + #jobName + '] has been DISABLED'
END
SET #subjectText = 'SQL Job on ' + #subjectText
-- # SEND EMAIL # --
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #profileName,
#recipients = #recipients,
#body = #bodyText,
#subject = #subjectText
END
try change the "FOR UPDATE" to "AFTER UPDATE, INSERT, DELETE"
this should run the trigger then for inserts and deleted from the table
you can then check if its an update , insert or delete by running something like
DECLARE #Type as varchar(1);
SET #Type = (
CASE
WHEN EXISTS(SELECT * FROM INSERTED) AND EXISTS(SELECT * FROM DELETED) THEN 'U' -- then the record was updated.
WHEN EXISTS(SELECT * FROM INSERTED) THEN 'I' --the record was inserted.
WHEN EXISTS(SELECT * FROM DELETED) THEN 'D' --the record was delete.
ELSE NULL
END)

SQL Server 2008: trying to export my data to xls file and data not displaying in rows

I have a sql query wich imports Data from a csv file and then matches that data with records on my database to make sure that records do exist, when thats done It then exports the file to an xls file, when It export to the file the result set all outputs in a single line insted of rows like It imported. eg. imported rows 10, matched 7. exported rows 1 intead of 7:
DROP TABLE CSVdataRaw,#FileList,#TmpID/#Failures,#Success,/ --,#ReverseFile
IF NOT EXISTS (SELECT * FROM SYS.tables WHERE name = 'CSVdataRaw')
BEGIN
CREATE TABLE CSVdataRaw
(
CellNumber varchar(12),
SMS_MSG varchar(250)
)
END
Create Table #FileList (
SMSFilename Varchar(512))
Declare #Path varchar(256) = 'dir C:\FileImport\Inbox\'
Declare #Command varchar(1024) = #Path+' /A-D /B'
--PRINT #Command
Insert #FileList
Exec Master.dbo.xp_cmdshell #Command
delete #FileList where SMSFilename is Null
Declare #File varchar (255) =
( SELECT top 1 * FROM #FileList
where SMSFilename like 'SMS%')
print #File
Declare #SMSFilename Varchar (255)
Set #SMSFilename = 'C:\FileImport\Inbox\'
Set #SMSFilename = #SMSFilename + #File -- + ''''
declare #BulkInsert varchar(MAX);
set #BulkInsert = 'BULK INSERT [CSVdataRaw]
From ' + char(39) + #SMSFilename +char(39)+
' With (ROWTERMINATOR = ''\n'', FIELDTERMINATOR = '','', Firstrow = 1)'
--print #BulkInsert
exec(#BulkInsert)
ALTER TABLE CSVdataRaw ADD ID INT IDENTITY
GO
alter table CSVDataRaw add Matterno Varchar (50)
GO
update CSVDataRaw set Matterno = (SELECT TOP 1 H_MID FROM History WHERE H_PhoneNumber = CSVDataRaw.CellNumber)
GO
alter table CSVDataRaw add H_Description varchar(50)
GO
update CSVdataRaw set H_Description = (select top 1 H_IDX from History with (nolock) where H_Description = CSVdataRaw.SMS_MSG)
GO
delete from CSVDataRaw where Matterno is null
CREATE TABLE #TmpID
(
ID INT,
Note VARCHAR(255)
)
DECLARE #Line varchar(MAX)
DECLARE #FileName varchar(255)
DECLARE #Row int
--INSERT HEADER
SET #FileName = 'C:\FileImport\SMS_History_' + replace(replace(replace(CONVERT(varchar,getdate(),120),' ',''),'-',''),':','') + '.xls'
SET #Line = 'Profile=0,Product=0,Client=0,ImportType=20,Delimiter= ,' + CHAR(13) + CHAR(10)
DELETE #TmpID
Insert into #TmpID (ID, Note)
select CellNumber, SMS_MSG
from CSVDataRaw
SELECT #Line = #Line + Note FROM #TmpID
--print #Line
EXEC dbo.uspWriteToFile #FileName, #Line
--print #Line
DROP TABLE CSVdataRaw,#TmpID,#FileList
Create Table #FileList (
SMSFilename Varchar(512))
Declare #Path varchar(256) = 'dir C:\FileImport\Inbox\'
Declare #Command varchar(1024) = #Path+' /A-D /B'
Insert #FileList
Exec Master.dbo.xp_cmdshell #Command
delete #FileList where SMSFilename is Null
Declare #File varchar (255) =
(SELECT top 1 * FROM #FileList
where SMSFilename like 'SMS%')
print #File
Declare #SMSFilename Varchar (255)
Set #SMSFilename = 'move /y C:\FileImport\Inbox\ C:\FileImport\Archive\' --Here you are setting a variable
Set #SMSFilename = #SMSFilename + #File + ''''
exec xp_cmdshell 'move /y C:\FileImport\Inbox\ C:\FileImport\Archive' --This part you are actually MOVING the file
DROP TABLE #FileList

When I am trying to drop tables using below script , it seems not working.

I am trying to drop tables from each server. My Server 1 has 3 Databases and Server 2 has 6 and Server 3 has 8.
Below is the SQL Script that I wrote to perform the drop operation from each databases in in particular server. After I perform these operation.
DECLARE
#LoopId int,
#Command varchar(500),
#tblName varchar(100)
DECLARE #List TABLE
(
TableName sysname not null,
LoopId int not null identity(1,1)
)
-- Load with tables you wish to drop
INSERT #List (TableName)
SELECT name FROM [Morgage].sys.objects WHERE type = 'u' and name like '%JKL%'
SELECT name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
SELECT name FROM [Core].sys.objects WHERE type = 'u' and name like '%JKL%'
SET #LoopId = ##rowcount
-- Go through list and process each item
WHILE #LoopId > 0
BEGIN
SET #tblName = (SELECT TableName from #List where LoopId = #LoopId)
SET #Command = 'Drop table ' + #tblName
execute (#Command)
SET #LoopId = #LoopId - 1
END
Above query result says rows affected but then when i go and try to test is using below query. I do see everything. What my query did actually? Am I doing it right?
SELECT name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
Any help will be appreciated. Thanks.
Try this version of your script:-
DECLARE
#LoopId int,
#Command varchar(500),
#tblName varchar(100),
#dbName sysname
DECLARE #List TABLE
(
DBName sysname not null,
TableName sysname not null,
LoopId int not null identity(1,1)
)
-- Load with tables you wish to drop
INSERT #List (DBName, TableName)
SELECT 'Morgage',name FROM [Morgage].sys.objects WHERE type = 'u' and name like '%JKL%'
UNION
SELECT 'Scorecard',name FROM [Scorecard].sys.objects WHERE type = 'u'and name like '%JKL%'
UNION
SELECT 'Core',name FROM [Core].sys.objects WHERE type = 'u' and name like '%JKL%'
SET #LoopId = ##rowcount
-- Go through list and process each item
WHILE #LoopId > 0
BEGIN
SELECT #tblName = TableName, #dbName=DBName from #List where LoopId = #LoopId
SET #Command = 'USE ' + #dbName + ';if not exists(select 1 from sys.foreign_keys where parent_object_id=object_id(''' + #tblName + ''',''U'')' + char(10) + 'Drop table ' + #tblName + ';'
execute (#Command)
SET #LoopId = #LoopId - 1
END
Might be the queries are not committing by default. Try specify it explicitly

insert command SQL server -identity Pkey autoincrement - column name by type , in "where condition"

i would like to alter a stored procedure so i will not suplly the identity column name
INSERT INTO tablName ..... WHERE IDENTITY_Column = 10
can i tell sql server managment studio to just refer to the IDENTITY column so it will find
it by its type which is (at least in my tables a default) autoincremet PK ID type
You haven't really given enough code for us to see what you are trying to do but from the snippet in the question.
WHERE IDENTITY_Column = 10
You can just use
WHERE $IDENTITY = 10
for that (to filter against an identity column without specifying the name).
If you do actually need to lookup the column name then an easier way, avoiding deprecated views is
SELECT name
FROM sys.identity_columns
WHERE object_id = object_id('dbo.YourTable')
found this information by now .
that is the plain and simple version .
declare #tblName sysname = '______'--<== enter a table name
declare #NameOfIDColumn sysname =
(
SELECT Name
FROM syscolumns
WHERE COLUMNPROPERTY( id ,name, 'IsIdentity') = 1 and OBJECT_NAME(id)= #tblName )
select #NameOfIDColumn AS 'result'
you could add this as an option to display last row of a table soretd by its record#
declare #query VARCHAR(100) = 'Select Top 1 * FROM '+ #tblName +' Order BY ' + #IdentColumnName + ' desc' ;
EXEC (#query);
and to play around or even make it as a test page in a .net project
make this one as a stored proc that will outpout a message to a test page .
declare #tblName sysname = '______'--<== enter a table name
declare #IdentColumnName sysname =
(
SELECT Name
FROM syscolumns
WHERE COLUMNPROPERTY( id ,name, 'IsIdentity') = 1 and OBJECT_NAME(id)= #tblName )
declare #result VARCHAR (50) = #tblName + ' Identity Column is ' + #IdentColumnName;
select #result AS 'result'
and with a shorter version of "idntity column search", by Martin Smith
declare #tblName sysname = '______'--<== enter a table name
declare #IdentColumnName sysname =
(SELECT name FROM sys.identity_columns WHERE object_id = object_id(#TableName))
declare #result VARCHAR (50) = #tblName + ' Identity Column is ' + #IdentColumnName;
select #result AS 'result'
this is related to a table copy trick i was trying to pull via stored procedure.
USE [YourDataBaseName]
GO
/****** Object: StoredProcedure [dbo].[Utils_TableRowCopy] Script Date: 10/03/2012 18:26:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Utils_TableRowCopy](
#TableName VARCHAR(50) ,
#RowNumberToCopy INT
)
AS
BEGIN
declare #RowIdentity sysname =
(
SELECT name FROM sys.identity_columns WHERE object_id = object_id(#TableName)
)
DECLARE #columns VARCHAR(5000), #query VARCHAR(8000);
SET #query = '' ;
SELECT #columns =
CASE
WHEN #columns IS NULL THEN column_name
ELSE #columns + ',' + column_name
END
FROM INFORMATION_SCHEMA.COLUMNS
WHERE (
TABLE_NAME = LTRIM(RTRIM(#TableName))
AND
column_name <> LTRIM(RTRIM(#RowIdentity))
);
SET #query = 'INSERT INTO ' + #TableName + ' (' + #columns + ') SELECT ' + #columns + ' FROM ' + #TableName + ' WHERE ' + #RowIdentity + ' = ' + CAST(#RowNumberToCopy AS VARCHAR);
--SELECT SCOPE_IDENTITY();
declare #query2 VARCHAR(100) = ' Select Top 1 * FROM '+ #TableName +' Order BY ' + #RowIdentity + ' desc' ;
EXEC (#query);
EXEC (#query2);
END

How to CREATE TYPE type_name AS existing_table_name

Is there a way to create table type in SQL Server 2008 based on scheme of existing table?
CREATE TABLE A (id INT, name VARCHAR(30))
CREATE TYPE type_a AS TABLE.A
Something like that.
No, this kind of composable DML is not yet possible. Microsoft has rejected this suggestion in the past, but with enough votes (e.g. more than 1!) it may get reconsidered in the future:
http://connect.microsoft.com/SQLServer/feedback/details/294130/table-valued-parameters-add-support-for-create-type-type-from-table-table-name-options-syntax-construct
You can use following stored procedure to create a type with same schema existing table may have.
Create PROCEDURE [dbo].[Sp_DefineTypeOutOfTableSchema]
#TableNames NVARCHAR(500)
AS
BEGIN
DECLARE #TableName NVARCHAR(100)
DECLARE #strSQL NVARCHAR(max)
DECLARE #strSQLCol NVARCHAR(1000)
DECLARE #ColName NVARCHAR(100)
DECLARE #ColDataTaype NVARCHAR(50)
DECLARE #ColDefault NVARCHAR(50)
DECLARE #ColIsNulable NVARCHAR(50)
DECLARE #ColCharMaxlen NVARCHAR(50)
DECLARE #ColNumPrec NVARCHAR(50)
DECLARE #ColNumScal NVARCHAR(50)
IF LEN(#TableNames) > 0 SET #TableNames = #TableNames + ','
WHILE LEN(#TableNames) > 0
BEGIN
SELECT #TableName = LTRIM(SUBSTRING(#TableNames, 1, CHARINDEX(',', #TableNames) - 1))
DECLARE schemaCur CURSOR FOR
SELECT COLUMN_NAME,DATA_TYPE,IS_NULLABLE,COLUMN_DEFAULT,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =#TableName
OPEN schemaCur
SELECT #strSQL=''
FETCH NEXT FROM schemaCur
INTO #ColName,#ColDataTaype,#ColIsNulable,#ColDefault,#ColCharMaxlen,#ColNumPrec,#ColNumScal
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #strSQLCol=''
SELECT #strSQLCol= '['+#ColName+'] '+'[' + #ColDataTaype +'] '
IF #ColDataTaype='nvarchar' or #ColDataTaype='char' or #ColDataTaype='varchar' or #ColDataTaype='vchar'
BEGIN
SELECT #strSQLCol=#strSQLCol+ '(' + #ColCharMaxlen +') '
END
ELSE IF #ColDataTaype='numeric' or #ColDataTaype='decimal'
BEGIN
SELECT #strSQLCol=#strSQLCol +'(' + #ColNumPrec +',' +#ColNumScal + ') '
END
IF #ColIsNulable='YES'
BEGIN
SELECT #strSQLCol=#strSQLCol+ 'NULL '
END
ELSE
BEGIN
SELECT #strSQLCol=#strSQLCol+ ' NOT NULL '
END
IF #ColDefault IS NOT NULL
BEGIN
SELECT #strSQLCol=#strSQLCol+ ' DEFAULT(' +#ColDefault + '),'
END
ELSE
BEGIN
SELECT #strSQLCol=#strSQLCol+ ' ,'
END
SELECT #strSQL=#strSQL+#strSQLCol
--print #strSQL
FETCH NEXT FROM schemaCur
INTO #ColName,#ColDataTaype,#ColIsNulable,#ColDefault,#ColCharMaxlen,#ColNumPrec,#ColNumScal
END
CLOSE schemaCur
DEALLOCATE schemaCur
--print #strSQL
SELECT #strSQL=left( #strSQL, len(#strSQL)-1)
--print #strSQL
IF EXISTS (SELECT * FROM sys.types WHERE IS_TABLE_TYPE = 1 AND name = 't_' +#TableName)
BEGIN
EXEC('DROP TYPE t_' +#TableName )
END
SELECT #strSQL = 'CREATE TYPE t_' + #TableName + ' AS TABLE (' + #strSQL + ')'
--print #strSQL
EXEC (#strSQL)
SELECT #TableNames = SUBSTRING(#TableNames, CHARINDEX(',', #TableNames) + 1, LEN(#TableNames))
END
END
you can use it like this
Exec Sp_DefineTypeOutOfTableSchema 'Table1name,Table2name'
You could experiment with creating a function that pulled the table definition out of sysobjects, systypes, syscolumns, syscomments, etc., and built a CREATE statement out of it. You'd just have to make sure to grab all of the important pieces (columns, constraints, comments, etc.) from the various sys tables.
Then call it like... EXEC myCREATEtable #template_table_name or some such...