ftp xp_cmdshell script within a stored procedure - sql-server

I'm building a stored procedure to transfer data from SQL Server to a remote FTP server.
I wrote the table data to a file with the following query
exec xp_cmdshell "bcp master.dbo.table out c:\temp\bcp_outputFile.txt -S(local)\SQLEXPRESS -T -c"
However, I'm struggling with building a script that would take that file and send it across to the FTP Server.
Using SSIS is not an option. It must be done with the xp_cmdshell command.
Any ideas?
Thanks

Use the below mention procedure for uploading the file in the ftp server.
here in the procedure i have hard coded the ftp details you can change it.
create procedure [dbo].[uploadfile_ftp]
#SourcePath varchar(128),
#SourceFiles varchar(128),
#DestPath varchar(128)
AS
Begin
DECLARE #FTPServer varchar(128)
DECLARE #FTPUser varchar(128)
DECLARE #FTPPwd varchar(128)
DECLARE #FTPMode varchar(10)
-- FTP attributes.
SET #FTPServer = 'ftp url'
SET #FTPUser = 'ftp username'
SET #FTPPwd = 'ftp password'
SET #FTPMode = 'binary' -- ascii, binary or blank for default.
DECLARE #cmd varchar(1000)
DECLARE #workfile varchar(128)
DECLARE #nowstr varchar(25)
-- Get the %TEMP% environment variable.
DECLARE #tempdir varchar(128)
CREATE TABLE #tempvartable(info VARCHAR(1000))
INSERT #tempvartable EXEC master..xp_cmdshell 'echo %temp%'
SET #tempdir = (SELECT top 1 info FROM #tempvartable)
IF RIGHT(#tempdir, 1) <> '\' SET #tempdir = #tempdir + '\'
DROP TABLE #tempvartable
-- Generate #workfile
SET #nowstr = replace(replace(convert(varchar(30), GETDATE(), 121), ' ', '_'), ':', '-')
SET #workfile = 'FTP_SPID' + convert(varchar(128), ##spid) + '_' + #nowstr + '.txt'
-- Deal with special chars for echo commands.
select #FTPServer = replace(replace(replace(#FTPServer, '|', '^|'),'<','^<'),'>','^>')
select #FTPUser = replace(replace(replace(#FTPUser, '|', '^|'),'<','^<'),'>','^>')
select #FTPPwd = replace(replace(replace(#FTPPwd, '&', '^&'),'<','^<'),'>','^>')
select #DestPath = replace(replace(replace(#DestPath, '|', '^|'),'<','^<'),'>','^>')
IF RIGHT(#SourcePath, 1) <> '\' SET #SourcePath = #SourcePath + '\'
-- Build the FTP script file.
select #cmd = 'echo ' + 'open ' + #FTPServer + ' > ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
print #cmd;
select #cmd = 'echo ' + #FTPUser + '>> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
print #cmd;
select #cmd = 'echo ' + #FTPPwd + '>> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
print #cmd;
select #cmd = 'echo ' + 'prompt ' + ' >> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
print #cmd;
IF LEN(#FTPMode) > 0
BEGIN
select #cmd = 'echo ' + #FTPMode + ' >> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
END
IF LEN(#DestPath) > 0
BEGIN
select #cmd = 'echo ' + 'cd ' + #DestPath + ' >> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
END
select #cmd = 'echo ' + 'mput ' + #SourcePath + #SourceFiles + ' >> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
select #cmd = 'echo ' + 'quit' + ' >> ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
-- Execute the FTP command via script file.
select #cmd = 'ftp -s:' + #tempdir + #workfile
print #cmd;
create table #a (id int identity(1,1), s varchar(1000))
insert #a
EXEC master..xp_cmdshell #cmd
select id, ouputtmp = s from #a
-- Clean up.
drop table #a
select #cmd = 'del ' + #tempdir + #workfile
EXEC master..xp_cmdshell #cmd
End

Related

Ignore null's in exported .csv file, bcp utility

How can I ignore null's in my exported .csv file, I used bcp utility
within sql server, here it is how this looks like altogether.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID ('[dbo].[generateCSV]') IS NOT NULL
DROP PROCEDURE [dbo].[generateCSV]
GO
CREATE PROCEDURE [dbo].[generateCSV]
(
#table varchar(100),
#output varchar(100),
#date varchar(12),
#server varchar(30)
)
AS
DECLARE #sql varchar(8000)
SELECT #sql = 'bcp "select * from ' + DB_NAME() + '.dbo.' + #table + '
where reportingdate = ''' + #date + '''"' + ' queryout ' + #output + ' -c
-C65001 -t";" -r"\n" -T -S' + #server
exec master..xp_cmdshell #sql
-- Main EXEC
EXEC dbo.generateCSV #table = 'Clients', #date = '2017-10-31', #output =
'//172.18.16.109/share/Test.csv (server with export target location ) ',
#server = '172.18.16.108(server we are connected to and from which we are
taking the data)'
After exporting and opening my file in notepad++ empty columns end up filled with NULL's.
What I want it to look like is...
Edit:
I included ISNULL() in my select clause but still notepad will read those columns as null valued.
SELECT #sql = 'bcp "select
ReportingDate,uniqClientID,registrationNumber,name,ISNULL(vatNumber,'''') as
vatNumber,ISNULL(entityStatusCode,'''') as entityStatusCode,
maximumLifetimeDPD from ' + DB_NAME() + '.dbo.' +
#table + ' where ReportingDate = ''' + #date + '''"' + ' queryout ' +
#output + ' -c -C65001 -t";" -r"\n" -T -S' + #server
SELECT #sql = 'bcp "select * from ' + DB_NAME() + '.dbo.' + #table +
' where reportingdate = ''' + #date + '''"' + ' queryout ' + #output
+ ' -c
-C65001 -t";" -r"\n" -T -S' + #server
Instead of SELECT * write the specific column names.
Wherever you feel NULL can appear you can write like following.
....
SELECT
Column1,
ISNULL(Column2,'') AS Column2,
Column3,
....
from ' + DB_NAME() + '.dbo.' + #table
.....
Note: If you have INT as datatype, you need to slightly change your select according to following query.
DECLARE #INTVAL INT
SET #INTVAL = NULL
SELECT
ISNULL(LTRIM(NULLIF(#INTVAL, 0)), '') AS ColumnName

How to read from a file which has SQL script which needs to be executed on multiple DBs on same server

Below script suppose to be executed on multiple DBs, however on parsing gives below error-
Msg 102, Level 15, State 1, Line 40
Incorrect syntax near '+'.
declare #list table (name varchar(128) not null);
fill the list with your custom subset
insert into #list
select name from sys.databases where name like '%connect%';
--select * from #list
--select min(name) from #list
--read the script
declare
#DBServerName varchar(128),
#FilePathName varchar(128),
#DBName varchar(128)
;
set #DBServerName = 'peeyushp-w8';
set #FilePathName = 'D:\script.sql';
set #DBName = '';
--EXEC xp_cmdshell 'sqlcmd -S ' + #DBServerName + ' -d ' + #DBName + ' -i ' + #FilePathName
declare
#db varchar(128),
#t varchar(max),
#s varchar(max)
;
--set #t = 'use {db}; exec sp_spaceused';
set #db = (select min(name) from #list);
while #db is not null
begin
--set #s = replace(#t, '{db}', ' -d' + #db);
--exec (#s);
EXEC xp_cmdshell 'sqlcmd -S ' + #DBServerName + #s + ' -i ' + replace(#FilePathName, '{db}', ' -d' + #db);
set #db = (select min(name) from #list where name > #db);
end
GO
Error is coming on 'xp_cmdshell' exec statement. Am i missing something which to be included in my SQL script. Will appreciate any help on the same.
According to PROCEDURE's Limitations and Restrictions in T-SQL :
You cannot specify a function name as a parameter default value or as the value passed to a parameter when executing a procedure. However, you can pass a function as a variable as shown in the following example.
So, it is impossible to use directly the string concatenation as procedure parameter. It must be declared before :
DECLARE #cmd VARCHAR(400)
SET #cmd = 'sqlcmd -S ' + #DBServerName + ' -d ' + #DBName + ' -i ' + #FilePathName
-- Now you can use it
EXEC xp_cmdshell #cmd

SQL BCP invalid object name ##Labels

I'm having trouble with BCP. It keeps saying invalid object name ##Labels despite me creating a global table. What am I doing wrong please?
The code is: -
DECLARE #SQL varchar(max)
SET #BatchNo = 'abc123'
DECLARE #test TABLE(A varchar(max),B varchar(max),C varchar(max),D varchar(max),E varchar(max),F varchar(max),G varchar(max),H varchar(max),I varchar(max),J varchar(max))
insert into #test values ('1','2','3','4','5','6','7','8','9','10')
SELECT * INTO ##Labels FROM #test
SET #SQL = 'SELECT * FROM ##Labels'
DECLARE #TMPfile varchar(25)
DECLARE #folder varchar(128)
DECLARE #LabelDir varchar(128)
DECLARE #template varchar(25)
DECLARE #FinalFile varchar(40)
DECLARE #cmdstr varchar(300)
SET #TMPfile = #BatchNo + '.tmp'
--Trigger folder
SET #folder = '\\WIN-0H\LABELLING\XFER\'
--Print Directive Folder
SET #LabelDir = '\\WIN-0H\DIR\'
--Label Data Template
SET #template = 'cl.csv'
--Fine output file
SET #FinalFile = #BatchNo + '.CHLABEL'
--Bulk Copy Query to csv temp file
SET #cmdstr = 'bcp "' + #SQL + '" QUERYout ' + #folder + #TMPfile + ' -c -t "," -T'
SELECT * FROM ##Labels
EXEC master..xp_cmdshell #cmdstr
PRINT #cmdstr
--join the label csv template to the actual data
SET #cmdstr = 'copy /Y /B ' + #LabelDir + #template + ' + ' + #folder + #TMPfile + ' ' + #folder + #FinalFile
EXEC master..xp_cmdshell #cmdstr
PRINT #cmdstr
--Remove all temporary files
SET #cmdstr = 'del ' + #folder + #TMPfile
EXEC master..xp_cmdshell #cmdstr
PRINT #cmdstr
PRINT 'Im Printing'
DROP TABLE ##Labels
The error message is:
Error = [Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid
object name '##Labels'.
The BCP command-line utility runs independently of the T-SQL script, even when inviked via xp_cmdshell. It connects to the default instance on the same server it runs on unless the BCP /S parameter specifies otherwise.
In this case, the global temp table was created on the named instance where the script ran. However, the BCP command connected to the default instance and the global temp table did not exist there (fortunately).

SQL Server BCP Command not Writing NVARCHAR(MAX) Variable Contents to File

I'm having issues with SQL Server's BCP. I'm not getting an error message but the command is also not writing anything to the path specified.
Here is my code:
In this scenario, the only variable not accounted for in the code below is #MESSAGE which is a NVARCHAR(MAX) and will take up most of that space so VARCHAR(8000) won't be nearly big enough.
DECLARE #OUTPUT_TABLE VARCHAR(255) = '##temp' + CONVERT(VARCHAR(12), CONVERT(INT, RAND() * 1000000))
DECLARE #RESULT INTEGER
DECLARE #OUTPUT_EXECUTION_COMMAND NVARCHAR(MAX) = 'CREATE TABLE [' + #OUTPUT_TABLE + '] ( CONTENT NVARCHAR(MAX) )
INSERT INTO [' + #OUTPUT_TABLE + ']
SELECT #MESSAGE'
EXECUTE SP_EXECUTESQL #OUTPUT_EXECUTION_COMMAND, N'#MESSAGE NVARCHAR(MAX)', #MESSAGE
DECLARE #OUTPUT_FILE_WRITE_COMMAND VARCHAR(1000) = 'BCP ”SELECT CONTENT FROM [' + #OUTPUT_TABLE + ']"
QUERYOUT "' + #FULL_PATH + '\' + #FILE_NAME + '" -w -T -S ' + ##servername
PRINT #OUTPUT_FILE_WRITE_COMMAND
EXECUTE #RESULT = master.sys.xp_cmdshell #OUTPUT_FILE_WRITE_COMMAND, NO_OUTPUT
PRINT #RESULT
EXECUTE ( 'DROP TABLE [' + #OUTPUT_TABLE + ']' )
So, the frustrating part is that I'm receiving an error, yet my file is not being written.
The output of PRINT #OUTPUT_FILE_WRITE_COMMAND is:
BCP ”SELECT CONTENT FROM [##temp878274]"
QUERYOUT "\\TXPDC-FS01\Profiles\cofarmer\My Sandbox\THCIC\Q2_2014\Burleson\PIPSUB2938718184092014251607.txt" -w -T -S TXPDC-STKSQL01
While the output of PRINT #RESULT is: 1
Yet nothing is being written. What am I doing wrong?
Looks like the issue is the line break in the#OUTPUT_FILE_WRITE_COMMAND (and the erroneous double quote”). Removing the line break worked for me:
DECLARE #OUTPUT_FILE_WRITE_COMMAND VARCHAR(1000) = 'BCP "SELECT CONTENT FROM [' + #OUTPUT_TABLE + ']" QUERYOUT "' + #FULL_PATH + '\' + #FILE_NAME + '" -w -T -S ' + ##servername
Result: 0 and the file was created.

Using varchar in the query syntax for BCP utility in SQL Server

I am trying to use BCP utility to export data with these commands, but I get an error in the query ...
I declared many variables, however my problem is with the query, due to I have to filter using a varchar column (CO_LIN is a varchar(6)), but if I use ' to wrap the value of the variable #LINEAPRODUCTO I got an error in SQL Server query tool, but if I do not use anything it give me this error:
Invalid column name 'MEN'
(MEN is the string value I set in the variable declaration)
DECLARE #PATH_ARC VARCHAR(200)
DECLARE #USUARIO VARCHAR(20)
DECLARE #PASSWORD VARCHAR(20)
DECLARE #TABLA VARCHAR(40)
DECLARE #SERVIDOR VARCHAR(100)
DECLARE #ARCHIVOSALIDA VARCHAR(200)
DECLARE #RUTAEJECUTAR VARCHAR(500)
DECLARE #MES VARCHAR(2)
DECLARE #DIA VARCHAR(2)
DECLARE #ANNO VARCHAR(4)
DECLARE #BASEDEDATOS VARCHAR(20)
DECLARE #LINEAPRODUCTO VARCHAR(6)
DECLARE #CONSULTA VARCHAR(300)
SET NOCOUNT ON;
-- Asignación de valores de las variables para la ejecución del stored procedure
SET #TABLA ='dbo.art'
SET #SERVIDOR = 'RJLD-LAPTOP\SQLEXPRESS'
SET #USUARIO = 'exp'
SET #PASSWORD = 'exp'
SET #PATH_ARC = 'C:\PRUEBA\'
SET #BASEDEDATOS = 'DEMO'
SET #LINEAPRODUCTO = 'MEN'
SET #MES = CAST(MONTH(GETDATE()) AS nchar(2))
IF LEN(RTRIM(LTRIM(#MES))) = 1
BEGIN
SET #MES = '0' + RTRIM(LTRIM(#MES))
END
SET #DIA = CAST(DAY(GETDATE()) AS nchar(2))
IF LEN(RTRIM(LTRIM(#DIA))) =1
BEGIN
SET #DIA = '0' + RTRIM(LTRIM(#DIA))
END
SET #ANNO = CAST(YEAR(GETDATE()) AS nchar(4))
SET #ARCHIVOSALIDA = 'RI_C58-L02_' + #ANNO + #MES + #DIA + '.txt'
SET #PATH_ARC = '"' + #PATH_ARC + #ARCHIVOSALIDA + '"'
SET #CONSULTA = '"select RTRIM(LTRIM(ITEM)),' + #ANNO + ',' + #MES + ',' + #DIA + ',CO_PROV from ' + #TABLA + ' WHERE CO_LIN=' + #LINEAPRODUCTO + '"'
SET #RUTAEJECUTAR = 'bcp ' + #CONSULTA + ' queryout ' + #PATH_ARC + ' -S ' + #SERVIDOR + ' -U ' + #USUARIO + ' -P ' + #PASSWORD + ' -c -t "|" -d ' + #BASEDEDATOS
-- select #RUTAEJECUTAR
EXEC xp_cmdshell #RUTAEJECUTAR
I'm not familiar with the BCP utility, but what I see happening is the same thing I'm seeing in the code formatting StackOverflow is using. Notice how the slash after PRUEBA is resulting in the following apostrophe not being recognized. I found another problem here where someone was having to get around the BCP utility using the slash as the escape character.
If the slash in the filepath is registering as an escape character, then the following code should work:
SET #PATH_ARC = 'C:\\PRUEBA\\'
SET #BASEDEDATOS = 'DEMO'
SET #LINEAPRODUCTO = 'MEN'
Notice that with the code above, the StackOverflow formatting is reading it correctly too.
Hope this helps!

Resources