I am using SQL Server 2017 Express edition on Microsoft Windows 10. I want to import all text files in a directory into a database at one time. My idea is that that SQL Server loops over the files in that directory and imports them all at the same time. Is there a way that I can achieve this?
Best Regards,
declare #dir varchar(1000) = 'C:\Temp';
declare #command varchar(1000);
declare #files table (id int identity, filename varchar(1000));
set #command = 'dir /b ' + #dir;
insert into #files execute xp_cmdshell #command;
declare commands cursor for
select 'bulk insert <your table name here> from ''' + #dir + '\' + filename + ''' <other options, WITH FORMAT, etc. here>;' from #files;
open commands;
fetch commands into #command;
while (##fetch_status = 0) begin
--print #command;
execute(#command);
fetch commands into #command;
end;
close commands;
deallocate commands;
Modify #dir and the bulk insert command that is being build and you're done.
You may have to enable 'xp_cmdshell', and this could be a problem for your DBA; and using 'execute' is always a potential issue (SQL injection, etc.).
To enable xp_cmdshell:
-- To allow advanced options to be changed.
EXEC sp_configure 'show advanced options', 1;
GO
-- To update the currently configured value for advanced options.
RECONFIGURE;
GO
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1;
GO
-- To update the currently configured value for this feature.
RECONFIGURE;
GO
As noted in another answer, xp_commandshell is problematic. SQL Server 2016+ allows another approach. See example
declare #tbl table(fn varchar(255), depth int,[isfile] int,primary key(fn))
declare #dir varchar(50)='C:\temp\' --'starting dir
insert #tbl
EXEC Master.dbo.xp_DirTree #dir,1,1 --dir, depth (1 - current only), file (0 - dirs only, 1+ - dirs and files)
delete #tbl where [isfile]=0 or fn not like '%.txt' --keep .txt files only
--select * from #tbl
--will insert into this table
create table #fileTbl (id int identity(1,1) primary key,fn varchar(255),txt varchar(max))
declare #fn varchar(255), #query nvarchar(4000)
select top 1 #fn=fn from #tbl
while ##ROWCOUNT>0--number of rows from the last query executed
begin
--dynamic query required to build OPENROWSET
set #query='insert #fileTbl(fn,txt) select '''+#dir+#fn+''',BulkColumn from openrowset(bulk ''c:\temp\'+#fn+''',single_blob) t'
exec sp_executesql #query
delete #tbl where fn=#fn
select top 1 #fn=fn from #tbl --proceed
end
select * from #fileTbl
Related
I have the following procedure which takes as parameter the name of database and the path and then creates a directory. My problem here I need override on the folder or delete it and then create a new one any idea of how to do such a thing
NOTE: this procedure creates in folder in depth of 0 and 1
ALTER PROCEDURE[dbo].[SP_CreateFolder]
#P_PATH VARCHAR(100),
#P_DBName VARCHAR(100)
AS
DECLARE #DBName sysname
DECLARE #DataPath nvarchar(500)
DECLARE #LogPath nvarchar(500)
DECLARE #DirTree TABLE (subdirectory nvarchar(255), depth INT)
-- Initialize variables
SET #DBName = #P_DBName
SET #DataPath = #P_PATH
-- #DataPath values
INSERT INTO #DirTree(subdirectory, depth)
EXEC master.sys.xp_dirtree #DataPath
SELECT * FROM #DirTree
-- Create the #DataPath directory
--IF (SELECT depth from #DirTree)!= 1
--EXEC master.dbo.xp_Delete_file #DBName
IF NOT EXISTS (SELECT 1 FROM #DirTree WHERE subdirectory = #DBName)
BEGIN
EXEC master.dbo.xp_create_subdir #DataPath
END
-- Remove all records from #DirTree
DELETE FROM #DirTree
First, the caveat: using T-SQL to operate on the file system is usually not a good idea, and there are a lot of risks assumed when doing it.
That said, you can use xp_cmdshell with the command-line syntax for whatever you want to do (deleting a folder, etc.), like this:
declare #rmdircmd nvarchar(280)
declare #dirname nvarchar(280)
set #dirname = '"C:\blah\blah\"'
set #rmdircmd = N'RMDIR ' + #dirname + ' /S /Q'
exec master.dbo.xp_cmdshell #rmdircmd, no_output
Good luck!
I have read some arts about BCP or CLR code that will export BLOBs to individual files on the hard drive, but I need to BCP or CLR out the entire table data together (meaning the other columns which are character or integer or datetime data need to come out as a whole) I need to make sure I can BCP/CLR the data back into the table and have the same linking between BLOBs and other column data.
Any ideas?
I'm not sure if I understand what you're asking, so I'll try to cover two cases.
First, if you'd like to export all your data (including varbinary blobs) into one file, you can do it. Here's a test script to use with your table. You have to turn on SQLCMD mode in your SSMS. Then issue this script:
-- create target structure same as source
select top 0 *
into YourTbl2
from YourTbl
-- first line makes BCP dump to file, second line imports it to target structure
!!bcp YourDb.dbo.YourTbl out "D:\Temp\BlobTest.bak" -T -c
!!bcp YourDb.dbo.YourTbl2 in "D:\Temp\BlobTest.bak" -T -c
-- test if everything is imported
select * from Playground.dbo.BlobTest
except
select * from Playground.dbo.BlobTest2
If you want to just export an individual file to disk where your SQL Server resides, you can use this:
!!bcp "SELECT TOP 1 YourBlob FROM YourDb.dbo.YourTbl" queryout "D:\Temp\YourFile.xyz" -T -c
If it's applicable, you can share the folder where you're exporting your blob and access it from your client PC.
You can do like the Following :
You can have Image Data Type to Hold Any Files with in.
And, Please Read the Following Thoroughly to Understand.
I've implemented this in our Project. Simple and Fully Dynamic.
You just have to call :
Insert [tblTemp] (imageType,ImageFile) Select '.PDF',BulkColumn from Openrowset( Bulk 'C:\mak\A.PDF', Single_Blob) as tb
to Insert into the Table and
You can Use :
WriteBinaryToDisc 'C:\NEWF\','MAK','.PDF','DOC_TABLE','DOC_ID','DOC_IMAGE','WHERE DOC_ID=''25'''
to write back to the File System with Your specified Location and Extension.
I've used an tblTemp to hold all the Files.
--FIRST CHANGE THE CONFIGURATION TO ACTIVATE THIS FEATURE
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
EXEC sp_configure 'Ole Automation Procedures';
GO
--HOW TO WRITE FILES TO DIRECTLY SQL SERVER FROM DISC
CREATE TABLE [dbo].[tblTemp](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ImageType] [varchar] (10) NULL,
[ImageFile] [image] NULL
) ON [PRIMARY]
Insert [tblTemp] (imageType,ImageFile) Select '.PDF',BulkColumn from Openrowset( Bulk 'C:\mak\A.PDF', Single_Blob) as tb
-----------------------------------------------------
--HOW TO WRITE FILE TO DISC FROM SQL SERVER
--WriteBinaryToDisc 'C:\NEWF\','MAK','.PDF','DOC_TABLE','DOC_ID','DOC_IMAGE','WHERE DOC_ID=''25'''
ALTER PROCEDURE WriteBinaryToDisc
(
#Path VARCHAR(255),
#Filename VARCHAR(100),
#FileExt VARCHAR(4),
#TblName varchar(50),
#IDField VARCHAR(50),
#ImageField VARCHAR(50),
#WHERE VARCHAR(300)
)
AS
set nocount on
EXEC ('
DECLARE #SOURCEPATH VARBINARY(MAX),
#DESTPATH VARCHAR(MAX),
#ObjectToken INT,
#image_ID BIGINT
DECLARE IMGPATH CURSOR FAST_FORWARD FOR SELECT '+#ImageField+','+#IDField+' from '+#TblName+' '+#WHERE+'
OPEN IMGPATH
FETCH NEXT FROM IMGPATH INTO #SOURCEPATH, #image_ID
WHILE ##FETCH_STATUS = 0
BEGIN
SET #DESTPATH = '''+#Path+'\'+#Filename+'''+ CAST(#image_ID AS varchar)+'''+#FileExt+'''
EXEC sp_OACreate ''ADODB.Stream'', #ObjectToken OUTPUT
EXEC sp_OASetProperty #ObjectToken, ''Type'', 1
EXEC sp_OAMethod #ObjectToken, ''Open''
EXEC sp_OAMethod #ObjectToken, ''Write'', NULL, #SOURCEPATH
EXEC sp_OAMethod #ObjectToken, ''SaveToFile'', NULL, #DESTPATH, 2
EXEC sp_OAMethod #ObjectToken, ''Close''
EXEC sp_OADestroy #ObjectToken
FETCH NEXT FROM IMGPATH INTO #SOURCEPATH, #image_ID
END
CLOSE IMGPATH
DEALLOCATE IMGPATH
')
---------------------------------------------------------------
I have a SQL Server running on my Windows Server and, at a specific column of a table, I have the path for a Zip file (which in turn has the source of the data stored in the database). Some of these are not valid (do not match the data in database). I need to make SQL Server verify that these Zip files exist and that they match the column that stores the path and name of the zip file. This way I will delete the wrong file-path column correspondences.
you can use the undocumented proc xp_fileexist will return 1 if it exists and 0 otherwise
SET NOCOUNT ON
DECLARE #iFileExists INT
EXEC master..xp_fileexist 'c:\bla.txt',
#iFileExists OUTPUT
select #iFileExists
You can use xp_fileexist however please note it is undocumented and unsupported.
You can use SQLCLR, however you didn't bother specifying what version of SQL Server you're using, so it may not be relevant - and in any case it is disabled by default, and security policies prevent its use in some places.
You can use a #temp table and xp_cmdshell, however xp_cmdshell is typically disabled for the same reasons as SQLCLR.
/* if you need to enable xp_cmdshell:
exec master..sp_configure 'show adv', 1;
reconfigure with override;
exec master..sp_configure 'xp_cmdshell', 1;
reconfigure with override;
exec master..sp_configure 'show adv', 0;
reconfigure with override;
*/
SET NOCOUNT ON;
DECLARE
#file VARCHAR(1000),
#path VARCHAR(255),
#cmd VARCHAR(2048);
SELECT
#file = 'foo.zip',
#path = 'C:\wherever\';
SELECT #cmd = 'dir /b "' + #path + #file + '"';
CREATE TABLE #x(a VARCHAR(1255));
INSERT #x EXEC master..xp_cmdshell #cmd;
IF EXISTS (SELECT 1 FROM #x WHERE a = #file)
PRINT 'file exists';
ELSE
PRINT 'file does not exist';
DROP TABLE #x;
EDIT based on new requirements. It shows a list of files either in the table or in the database, and indicates whether the file is in only one location or both. It assumes that path + file is <= 900 characters long (merely to be able to use an index on at least one side).
USE tempdb;
GO
CREATE TABLE dbo.files(f VARCHAR(1000));
INSERT dbo.files(f) SELECT 'zip_that_does_not_exist.zip'
UNION ALL SELECT 'c:\path\file_that_does_not_exist.zip'
UNION ALL SELECT 'c:\path\file_that_exists.zip'
UNION ALL SELECT 'zip_that_exists.zip';
DECLARE
#path VARCHAR(255),
#cmd VARCHAR(2048);
SELECT
#path = path_column,
#cmd = 'dir /b "' + path_column + '"'
FROM
dbo.table_that_holds_path;
CREATE TABLE #x(f VARCHAR(900) UNIQUE);
INSERT #x EXEC master..xp_cmdshell #cmd;
DELETE #x WHERE f IS NULL;
UPDATE #x SET f = LOWER(f);
WITH f AS
(
SELECT f = REPLACE(LOWER(f), LOWER(#path), '')
FROM dbo.files
)
SELECT
[file] = COALESCE(x.f, f.f),
[status] = CASE
WHEN x.f IS NULL THEN 'in database, not in folder'
WHEN f.f IS NULL THEN 'in folder, not in database'
ELSE 'in both' END
FROM
f FULL OUTER JOIN #x AS x
ON x.f = f.f;
DROP TABLE #x, dbo.files;
I am working on an application where I need to get the SQL response as XML into an XML file (and to store it in some physical location, say c:\xyz.xml).
I am able to generate the XML content using the provisions available in SQL Server as shown below.
SELECT * FROM #Table FOR XML AUTO, ELEMENTS
where: #Table is a table variable.
I want to know how I can store the query output to an XML file from SQL Server itself.
There's one more option - use sqlcmd tool.
Add :XML ON as a first line in your SQL file (let's call it input.sql)
A command like this will do the trick:
sqlcmd -S <your-server> -i input.sql -o output.xml
You need to use xp_cmdshell, and the bcp utility in the following way
EXEC xp_cmdshell 'bcp "SELECT * FROM #Table FOR XML AUTO, ELEMENTS" queryout "C:\table.xml" -c -T'
Hit me back in the comments if you've got any questions or want to know anything more about how this works.
You can't write to the file system from SQL Server itself. At least not that easily. There are three alternatives:
use xp_cmdshell. I would strongly advise against it. By default xp_cmdshell is disabled for security purposes, and to have it enabled it just for this operation opens a way to big security hole in your system.
use the FileSystemObject and the OLE Automation procedures sp_OACreate/sp_OAMethod. See Reading and Writing Files in SQL Server using T-SQL. This, while marginally better than the xp_cmdshell option, it doesn't give a much better security story. The only reason why is better than xp_cmdshell is that is by far less known by hackers. But the OLE Automation procedures option in SQL Server is also disabled by default and enabling this option exposes the very same security problems xp_cmdshell has.
use a CLR procedure. This would be my recommendation. Create an assembly with digital signature, use the assembly signature to allow, through Transact-SQL code signing, EXTERNAL ACCESS, then use the CLR procedure to write the XML into the file system. While this is significantly more complex than the simple xp_cmdshell or OLE Automation options, it is the most controlable and granular one from a security point of view and is the easiest to maintain and get right (is .Net code as opposed to shell scripts). Unfortunately, by default the clr option is also disabled in the server and has to be enabled.
If you press
ctrl + shift + f
you will have selected "Results To File." This can be found in the Query menu on the top bar of Sql Management Studio.
Or put something like this into your sql script
exec xp_cmdshell 'bcp "select * from suppliers" queryout "c:\suppliers.txt" -S server -T'
See this link, there is an issue about whether it is the app's c drive or the sql server's c drive. Have fun sorting that out.
You can create CLR function that create the file, build it into the sql server, and use it from a stored procedure
Another way( I haven't tested it ) - There is a tool bcp
bcp "Select * from dbo..table FOR XML RAW" queryout c:\temp\test.xml -Soc-db -Uuser -Ppassword
This example is from here
Simple SQL Write to File method
DECLARE #xml XML = '<MyXML></MyXMl>'
DECLARE #strXML varchar(max) = convert(varchar(max),#XML)
-- Add white space for readability
SELECT #strxml = replace(#strxml,'</',char(13) + char(10) + '</')
--- Add Declartives, namespaces and xls
Create Table dbo.BCP_OUT(contents varchar(max))
INSERT INTO dbo.bcp_out(contents)
SELECT Convert(varchar(max),#strXML )
EXEC xp_cmdshell N'BCP -S SERVER [database].dbo.bcp_out -T -c -o \\pathto\file.name'
If your xml output is relatively small (<4000 characters), then you can use this SP:
IF EXISTS (SELECT TOP 1 1 FROM sys.objects WHERE object_id = OBJECT_ID('dbo.USP_WRITE_UNICODE_STRING_TO_FILE') AND type = 'P')
BEGIN
DROP PROCEDURE dbo.USP_WRITE_UNICODE_STRING_TO_FILE
END
GO
-- =============================================
-- Description: Writes the specified Unicode string to the specified file.
-- Permissions: This stored procedure uses xp_cmdshell which is disabled by default. To enable it:
-- 1. In Management Studio connect to a component of SQL Server.
-- 2. In Object Explorer, right-click the server, and then click Facets.
-- 3. In the View Facets dialog box, expand the Facet list, and select the Surface Area Configuration.
-- 4. In the Facet properties area, select XPCmdShellEnabled property and set its value to True.
-- 5. Click OK.
-- Example: EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE'<root> <a b="c" /> </root>', 'C:\Test.xml', 1;
-- =============================================
CREATE PROCEDURE dbo.USP_WRITE_UNICODE_STRING_TO_FILE
(
#Str NVARCHAR(4000),
#XmlFilePath NVARCHAR(256),
#Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Str1 NVARCHAR(MAX),
#Cmd NVARCHAR(4000),
#MaxLen int = 4000;
--see: http://technet.microsoft.com/en-us/library/bb490897.aspx
SET #Str1 = REPLACE(REPLACE(REPLACE(#Str, '>', '^>'), '<', '^<'), '"', '^"');
-- '>' Writes the command output to a file
SET #Str1 =N'ECHO ' + #Str1 + N'>"'+ #XmlFilePath + N'"';
IF #Debug = 1
BEGIN
DECLARE #Msg varchar(128) = 'The total lenght is ' + CAST(LEN(#Str1) AS VARCHAR(10)) + ' characters.'
PRINT #Msg;
PRINT #Str1;
END
IF (LEN(#Str1) > #MaxLen)
RAISERROR ('The input string is too long', 11, 0);
ELSE
SET #Cmd = CAST (#Str1 AS NVARCHAR(4000));
EXEC master..xp_cmdshell #Cmd, NO_OUTPUT;
END
GO
--Test 1
DECLARE #Str NVARCHAR(4000);
DECLARE #Xml xml = '<root> <a b="c" /> </root>';
SET #Str = CAST (#Xml AS NVARCHAR(4000));
EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE #Str, 'C:\Test.xml', 1;
GO
--Test 2
DECLARE #Str NVARCHAR(4000);
SET #Str = REPLICATE('a', 4000);
EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE #Str, 'C:\Test.xml', 1;
GO
If you don't work with Unicode, then you can create another SP: USP_WRITE_NON_UNICODE_STRING_TO_FILE, which will be very similar to the previous one with the following changes:
CREATE PROCEDURE dbo.USP_WRITE_NON_UNICODE_STRING_TO_FILE
(
#Str VARCHAR(8000),
#XmlFilePath NVARCHAR(256),
#Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Str1 VARCHAR(MAX),
#Cmd VARCHAR(8000),
#MaxLen int = 8000;
...
SET #Cmd = CAST (#Str1 AS VARCHAR(8000));
That SP allows the use of two times longer the input string (<8000 characters).
If your XML is longer than 8000 but less than 1MB you can use sqlcmd utility without :XML ON command. It greatly simplify the usage of the utility because you don't need a separate input_file with :XML ON command included. Here is an example:
DECLARE #Cmd NVARCHAR(4000);
SET #Cmd = N'sqlcmd -S ' + ##SERVERNAME + N' -d ' + DB_NAME() +
N' -Q "SET NOCOUNT ON; DECLARE #Xml xml = ''<root> <a >b</a> </root>''; SELECT CONVERT(NVARCHAR(MAX), #Xml);" -o "C:\Test.xml" -y 0';
PRINT #Cmd;
EXEC master..xp_cmdshell #Cmd, NO_OUTPUT;
You can also use an SP here:
CREATE PROCEDURE dbo.USP_SAMPLE_PROCEDURE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Xml xml;
SET #Xml = (SELECT name, type_desc FROM sys.objects FOR XML PATH('object'), ROOT('sys.objects'));
SELECT CONVERT(NVARCHAR(MAX), #Xml)
END
GO
DECLARE #Cmd NVARCHAR(4000);
SET #Cmd = N'sqlcmd -S ' + ##SERVERNAME + N' -d ' + DB_NAME() +
N' -Q "EXEC dbo.USP_SAMPLE_PROCEDURE;" -o "C:\Test.xml" -y 0';
PRINT #Cmd;
EXEC master..xp_cmdshell #Cmd, NO_OUTPUT;
GO
If your XML is more than 1MB you should use :XML ON command in a separate script and specify it as -i input_file parameter.
I made this SP so I can easily extract data from db or temp table to XML file on file system. It supports where clause.
CREATE PROCEDURE dbo.ExportToXMLFile
#TableName varchar(1000)
, #Where varchar(2000)=''
, #TicketNumber varchar(500)
, #debug bit=0
as
/*
Date:2016-03-27
Author: BojNed
Purpose: Exports data from table to XML file on filesystem.
#TableName = name of table to export.
#Where = optitional, to set #Where Clause. DO NOT ENTER WHERE at beggining of the string
#TicketNumber = To save to folder on filesystem
#Debug = Optitional. To debug this SP.
Examples:
EXEC dbo.ExportToXMLFile '#tt','columnX=2','221',0
EXEC dbo.ExportToXMLFile '[Production].[Product]','','252',1
EXEC dbo.ExportToXMLFile '[dbo].[DatabaseLog]','ColumnZ=55','351',0
EXEC dbo.ExportToXMLFile '[dbo].[DatabaseLog]','','7865',1
*/
begin
if #debug=0
SET NOCOUNT ON
declare #SQL nvarchar(max)
declare #IsTempTable bit
declare #NewTableName varchar(1000)
declare #Xml as XML
if (isnull(#TicketNumber,''))=''
begin
RAISERROR('No ticket number defined',16,1,1)
RETURN
END
--check if table is tmp or variable
if (SELECT SUBSTRING(#TableName,1,1))='#' or (SELECT SUBSTRING(#TableName,1,1))='#'
BEGIN
if #debug=1
PRINT 'Source is TMP table'
set #NewTableName='TMPTBL_'+#TableName
END
ELSE
BEGIN
if #debug=1
PRINT 'Source is db table'
set #NewTableName=replace(#TableName,'.','_')
END
--RemoveSpecialChars
declare #KeepValues varchar(1000)
set #KeepValues = '%[^a-z^0-9^_]%'
WHILE PATINDEX(#KeepValues,#NewTableName)>0
set #NewTableName = STUFF(#NewTableName, PATINDEX(#KeepValues,#NewTableName),1,'')
if #debug=1
PRINT 'Node name for XML Header and filename: '+#NewTableName
if ISNULL(#Where,'')=''
BEGIN
set #SQL= 'SELECT * FROM '+ #TableName+' FOR XML PATH, ROOT ('''+#NewTableName+'''), ELEMENTS'
if #debug=1
PRINT 'NO Where condition'
END
ELSE
BEGIN
set #SQL= 'SELECT * FROM '+ #TableName+' WHERE '+#Where+ ' FOR XML PATH, ROOT ('''+#NewTableName+'''), ELEMENTS'
if #debug=1
PRINT 'With Where condition'
END
--Get XML to tbl
if ISNULL(OBJECT_ID ('tempdb..##TXML'),0)>0
DROP TABLE ##TXML
CREATE TABLE ##TXML (XMLText XML)
set #SQL = ' insert into ##TXML select ('+#SQL+')'
--parse query
declare #testsql nvarchar(max)
declare #result int
set #testsql = N'set parseonly on; ' + #sql
exec #result = sp_executesql #testsql
-- If it worked, execute it
if #result = 0
begin
if #debug=1
PRINT 'Query OK: '+ #SQL
exec sp_executesql #sql
end
else
BEGIN
DECLARE #msg varchar(2000)
set #msg ='Parsing Error on query: ' + #SQL
RAISERROR (#msg,16,1,1)
RETURN
END
DECLARE #Tbl TABLE (id int identity(1,1), Dir varchar(256))
--check if dir exsists
INSERT into #Tbl
EXEC master.dbo.xp_subdirs 'C:\DataCorrectionBackup\'
if (SELECT Count(*) from #Tbl WHERE Dir=#TicketNumber)=0
BEGIN
--create new dir
DECLARE #t varchar(500)
set #t ='C:\DataCorrectionBackup\'+#TicketNumber
EXEC master.sys.xp_create_subdir #t
END
declare #bcp varchar(500)
declare #Filename VARCHAR(255)
set #Filename =convert(varchar(100),GETDATE(),112)+'_'+replace(convert(varchar(100),GETDATE(),114),':','')+'_'+#NewTableName+'.xml'
set #bcp = 'bcp "SELECT XMLText from ##TXML" queryout C:\DataCorrectionBackup\'+#TicketNumber+'\'+#Filename+' -w -T -S'+ ##servername
--save file
if #debug=0
EXEC xp_cmdshell #bcp, NO_OUTPUT
ELSE
BEGIN
EXEC xp_cmdshell #bcp
PRINT #bcp
END
DROP table ##TXML
end
go
I have a number of generated .sql files that I want to run in succession. I'd like to run them from a SQL statement in a query (i.e. Query Analyzer/Server Management Studio).
Is it possible to do something like this and if so what is the syntax for doing this?
I'm hoping for something like:
exec 'c:\temp\file01.sql'
exec 'c:\temp\file02.sql'
I am using SQL Server 2005 and running queries in management studio.
use xp_cmdshell and sqlcmd
EXEC xp_cmdshell 'sqlcmd -S ' + #DBServerName + ' -d ' + #DBName + ' -i ' + #FilePathName
Very helpful thanks, see also this link:
Execute SQL Server scripts
for a similar example.
To turn xp_cmdshell on and off see below:
On
SET NOCOUNT ON
EXEC master.dbo.sp_configure 'show advanced options', 1
RECONFIGURE
EXEC master.dbo.sp_configure 'xp_cmdshell', 1
RECONFIGURE
Off
EXEC master.dbo.sp_configure 'xp_cmdshell', 0
RECONFIGURE
EXEC master.dbo.sp_configure 'show advanced options', 0
RECONFIGURE
SET NOCOUNT OFF
Or just use openrowset to read your script into a variable and execute it (sorry for reviving an 8 years old topic):
DECLARE #SQL varchar(MAX)
SELECT #SQL = BulkColumn
FROM OPENROWSET
( BULK 'MeinPfad\MeinSkript.sql'
, SINGLE_BLOB ) AS MYTABLE
--PRINT #sql
EXEC (#sql)
This is what I use. Works well and is simple to reuse. It can be changed to read all files in the directory, but this way I get to control which ones to execute.
/*
execute a list of .sql files against the server and DB specified
*/
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
DECLARE #DBServerName VARCHAR(100) = 'servername'
DECLARE #DBName VARCHAR(100) = 'db name'
DECLARE #FilePath VARCHAR(200) = 'path to scrips\'
/*
create a holder for all filenames to be executed
*/
DECLARE #FileList TABLE (Files NVARCHAR(MAX))
INSERT INTO #FileList VALUES ('script 1.sql')
INSERT INTO #FileList VALUES ('script 2.sql')
INSERT INTO #FileList VALUES ('script X.sql')
WHILE (SELECT COUNT(Files) FROM #FileList) > 0
BEGIN
/*
execute each file one at a time
*/
DECLARE #FileName NVARCHAR(MAX) = (SELECT TOP(1) Files FROM #FileList)
DECLARE #command VARCHAR(500) = 'sqlcmd -S ' + #DBServerName + ' -d ' + #DBName + ' -i "' + #FilePath + #Filename +'"'
EXEC xp_cmdshell #command
PRINT 'EXECUTED: ' + #FileName
DELETE FROM #FileList WHERE Files = #FileName
END
COMMIT TRAN
I wouldn't recommended doing this, but if you really have to then the extended stored procedure xp_cmdshell is what you want. You will have to first read the contents of the file into a variable and then use something like this:
DECLARE #cmd sysname, #var sysname
SET #var = 'Hello world'
SET #cmd = 'echo ' + #var + ' > var_out.txt'
EXEC master..xp_cmdshell #cmd
Note: xp_cmdshell runs commands in the background, because of this, it must not be used to run programs that require user input.
Take a look at OSQL. This utility lets you run SQL from the command prompt. It's easy to get installed on a system, I think it comes with the free SQL Server Express.
Using the osql Utility
A qick search of "OSQL" on stack overflow shows a lot of stuff is available.
The main thing to handle properly is the user and password account parameters that get passed in on the command line. I have seen batch files that use NT file access permissions to control the file with the password and then using this file's contents to get the script started. You could also write a quick C# or VB program to run it using the Process class.
For Windows Authentication, if you are running as another user:
Open Command Prompt as your Windows user (Right click on it, Open File Location, Shift + Right Click, Run as a different user)
sqlcmd -S localhost\SQLEXPRESS -d DatabaseName-i "c:\temp\script.sql"
Or if you are using Sql Server user:
sqlcmd -S localhost\SQLEXPRESS -d DatabaseName-i "c:\temp\script.sql" -U UserName -P Password
Replace localhost\SQLEXPRESS with you server name if not local server.
Open windows command line (CMD)
sqlcmd -S localhost -d NorthWind -i "C:\MyScript.sql"
For anybody stumbling onto this question like I did and might find this useful, I liked Bruce Thompson's answer (which ran SQL from files in a loop), but I preferred Pesche Helfer's approach to file execution (as it avoided using xp_cmdshell).
So I combined the two (and tweaked it slightly so it runs everything from a folder instead of a manually created list):
DECLARE #Dir NVARCHAR(512) = 'd:\SQLScriptsDirectory'
DECLARE #FileList TABLE (
subdirectory NVARCHAR(512),
depth int,
[file] bit
)
INSERT #FileList
EXEC Master.dbo.xp_DirTree #Dir,1,1
WHILE (SELECT COUNT(*) FROM #FileList) > 0
BEGIN
DECLARE #FileName NVARCHAR(MAX) = (SELECT TOP(1) subdirectory FROM #FileList)
DECLARE #FullPath NVARCHAR(MAX) = #Dir + '\' + #FileName
DECLARE #SQL NVARCHAR(MAX)
DECLARE #SQL_TO_EXEC NVARCHAR(MAX)
SELECT #SQL_TO_EXEC = 'select #SQL = BulkColumn
FROM OPENROWSET
( BULK ''' + #FullPath + '''
, SINGLE_BLOB ) AS MYTABLE'
DECLARE #parmsdeclare NVARCHAR(4000) = '#SQL varchar(max) OUTPUT'
EXEC sp_executesql #stmt = #SQL_TO_EXEC
, #params = #parmsdeclare
, #SQL = #SQL OUTPUT
EXEC (#sql)
DELETE FROM #FileList WHERE subdirectory = #FileName
PRINT 'EXECUTED: ' + #FileName
END