Execute BCP command in remote server - sql-server

i am facing an issue while executing the BCP command in the remote server.
i have the following command in a batch file which executes a script file.
The script file process a temporary table and writes the records in temporary table to a file.
SQLCMD -SQA_Server236 -dtestdb -Usa -PPassword1 -i"D:\script\Writing to Files\Write to CSV.sql" -o"D:\script\script_logs.log"
--script files contains...
declare #table NVARCHAR(255)
declare #filename VARCHAR(100)
set #filename='C:\TextFile\abcd.csv'
set #table ='##Indexes_Add'
IF OBJECT_ID('tempdb..#Indexes_Add') IS NOT NULL
BEGIN
DROP TABLE ##Indexes_Add
END
CREATE TABLE ##Indexes_Add
(
id int IDENTITY(1,1) PRIMARY KEY,
alter_command NVARCHAR(MAX),
successfully_readded BIT NULL,
)
insert into ##Indexes_Add select 'a',0
insert into ##Indexes_Add select 'a',0
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..'+#table) IS NOT NULL
BEGIN
DECLARE
#sql NVARCHAR(MAX),
#cols NVARCHAR(MAX) = N'';
SELECT #cols += ',' + name
FROM tempdb.sys.columns
WHERE [object_id] = OBJECT_ID('tempdb..'+#table)
ORDER BY column_id;
SELECT #cols = STUFF(#cols, 1, 1, '');
SET #sql = N'EXEC master..xp_cmdshell ''bcp "SELECT '''''
+ REPLACE(#cols, ',', ''''',''''') + ''''' UNION ALL SELECT '
+ 'RTRIM(' + REPLACE(#cols, ',', '),RTRIM(') + ') FROM '
+ 'tempdb.dbo.'+#table + '" queryout "' + #filename + '" -c -t, -SQA_Server236 -Usa -PPassword1''';
EXEC sp_executesql #sql;
print #sql
END
My problem-:
When i run the above batch command in a batch file and i give my local server other than server name "QA_Server236" , i am getting the file "abcd.csv" created in my system but when i give the server name as "QA_Server236" the file is created in the remote machine i.e QA_Server236. But i want the file to be created in my system if the given server is a remote server say "QA_Server236"
Can anyone help me in this issue. i am not getting any method to do so.

If I'm right BCP does not allow saving result sets and/or logs to remote machines. But you could try to mount a folder on remote PC to a shared folder on your local machine and set the output location there, or maybe try using network path "\[YOURPC]....".As I'm not sure it works (actually, I think it won't), here's the only solution I can think of: add a line to your batch which moves the file(s) from the remote machine to your PC (xcopy or similar) after BCP finished executing (in batch, do this as "Call bcp.exe [params]" instead of just "bcp.exe ...")Hope this helps!

Related

SQL Server 2008 R2: Export data using bcp command and store bcp output into variable

I want to export data using bcp command and the output of the bcp command should be stored in the variable.
My try:
DECLARE #Result varchar(max)
DECLARE #SQL nvarchar(max)
SET #SQL = N'Execute xp_cmdshell ''bcp "SELECT * FROM EMP" QueryOut "E:\BCP\Result.pec" -T -t#_# -c -o "E:\BCP\LogReport.txt"'''
EXEC sp_executesql #SQL, N'#Result nvarchar(75) OUTPUT', #Result =#Result output
PRINT(#Result)
But getting an error in the output:
output
------------------------------------------------------------------------------
bcp: Unable to open output file E:\BCP\LogReport.txt: No such file or directory
NULL
Questions:
1. How to store the above output result into the variable?
2. Given permission to the file and folder too, but still getting this error.
---------------------------------------- 1 -------------------------------------------
DECLARE #Result TABLE
(error_msg VARCHAR(800))
DECLARE
#SQL varchar(8000),
#Result_var VARCHAR(MAX)=''
SET #SQL = N'bcp "SELECT * FROM <MY_DATABASE>.<MY_SCHEMA>.<MY_TABLE>" QueryOut "E:\BCP\Result.pec" -T -t#_# -c -o "E:\BCP\LogReport.txt"'''
-- Insert the output from xp_cmdshell into the table #Result
INSERT INTO #Result (error_msg)
EXEC xp_cmdshell #SQL
-- Merge the rows
SELECT #Result_var = #Result_var + ' ' + ISNULL(error_msg,'') FROM #Result
-- Output in variable
PRINT #Result_var
--------------------------------------------------------------------------------------
2. For me, your command works, check access to folders and subfolders (for database user), check permissions on the sql server.

Cannot get the correct files in the folder using SQL xp_smdshell command

I have files in my computer's folder with following names:
XXX.IN.txt
YYY.TEST.NUM.txt
ABC.AA.Z100.X.E999567777.Y001.txt
ABC.AA.Z100.X.E999568888.Y002.txt
ABC.AA.Z100.X.E999568888.Y003.txt
I want to write a SQL statement that would insert files that have the above described structure into a table, so I can later on write some logic on them.
I already used the command line statement inside of my stored proc to check if files exist:
EXEC master.dbo.xp_fileexist #fullPath, #exist OUTPUT
SET #exist = CAST(#exist AS BIT)
Now, I need to find certain files containing string in their names. I have the statement to do that:
DECLARE #cmdLine VARCHAR(200)
DECLARE #fullPath VARCHAR(900) = '\\my_network_path\MyDir\'
DECLARE #filter VARCHAR(100) = 'ABC.AA.Z100.X.*.txt'
SET #cmdLine = 'dir "' + #fullPath + '"'
EXEC master..xp_cmdshell #cmdLine
Above command should give me the following files:
ABC.AA.Z100.X.E999567777.Y001.txt
ABC.AA.Z100.X.E999568888.Y002.txt
ABC.AA.Z100.X.E999568888.Y003.txt
CREATE TABLE #FileDetails
(
data VARCHAR(MAX)
)
INSERT #FileDetails(data) EXEC master..xp_cmdshell #cmdLine
But it lists all the .txt files in the folder
How would I do list only those files that I need
First of all, the #cmdline should be set higher than #fullpath since it's supposed to fit all of it in the end.
Second of all, unless I am looking at it wrong or you didn't correct it here, the #filter variable isn't being used, so it would show every file regardless of extension.
My Code:
DECLARE #cmdLine VARCHAR(2000)
DECLARE #fullPath VARCHAR(1000) = '\\my_network_path\MyDir\'
DECLARE #filter VARCHAR(100) = 'ABC.AA.Z100.X.*.txt'
SET #cmdLine = 'dir "' + #fullPath + #filter + '"'
EXEC master..xp_cmdshell #cmdLine
My Output (keep in mind I created a Test.txt in the same folder):
10-10-2017 12:17 0 ABC.AA.Z100.X.Y001.txt
10-10-2017 12:18 0 ABC.AA.Z100.X.Y002.txt
10-10-2017 12:18 0 ABC.AA.Z100.X.Y003.txt
I would do this with either a CLR proc or an SSIS Script that uses the FileSystemObject to iterate through the files, filter for the ones you want and build a SQL String and execute it.
I don't know any way to do what you want with just straight TSQL.

Trigger MSSQL - Output to File (XML)

we have a very old ERP system which is badly supported.
Now the warehouse want´s to buy a new "store system" for our goods. It´s a fully automatic store system which need´s data from our ERP system. The support of your ERP system can´t help us, so we have to build a solution of our own.
The idea was to "move" the items for the new storage system to a special storage place called (SHUT1) and output the "part number" and "quantity" to a file (xml) which can be read by the new software.
We can´t change anything in the software of our ERP system, so we have to do it on the SQL Server itself.
(I know, a trigger is not the "best" thing to do, but I have have no other choice)
CREATE TRIGGER tr_LagerShut ON dbo.Lagerverwaltung
AFTER INSERT
AS
BEGIN
IF (SELECT [Lagerort] from Inserted) = 'SHUT1'
BEGIN
DECLARE #Cmd VARCHAR(2000) ;
DECLARE #FormatDate4File VARCHAR(200);
SET #FormatDate4File = (SELECT(SYSUTCDATETIME()));
SET #FormatDate4File = (SELECT REPLACE(#FormatDate4File,' ','-'));
SET #FormatDate4File = (SELECT REPLACE(#FormatDate4File,':','-'));
SET #FormatDate4File = (SELECT REPLACE(#FormatDate4File,'.','-'));
SET #Cmd = ( SELECT [Artikelnummer],[Menge] FROM inserted FOR XML PATH('')) ;
SET #Cmd = 'Echo "' + #Cmd + '" >>"C:\Temp\' + #FormatDate4File +'.xml"' ;
EXEC xp_cmdshell #Cmd ;
END;
END;
The trigger "installs" fine, but if I change a storage place to a new one, the ERP system stalls with "ERROR" (there is no error description :(
If I drop the trigger the system is just running fine again. So I think there is a error in the trigger, but I can´t find it.
Can anybody help please?
Aleks.
Don't know what ERP system stalls with "ERROR" looks like... Frozend GUI? Timeout? Just no file created?
My magic glass bulb tells me the following: You are inserting more than one row at once. If so, this statement will break, because a comparison like this is only valid against a scalar value. If there is more than one row in inserted, this will not work:
IF (SELECT [Lagerort] from Inserted) = 'SHUT1'.
Your trigger can be simplified, but I doubt, that you will like the result. Check this with special characters (like üöä) and check for enclosing "-characters...
CREATE TRIGGER tr_LagerShut ON dbo.Lagerverwaltung
AFTER INSERT
AS
BEGIN
IF EXISTS(SELECT 1 FROM inserted WHERE [Lagerort]='SHUT1')
BEGIN
DECLARE #FileName VARCHAR(255) =REPLACE(REPLACE(REPLACE(SYSUTCDATETIME(),' ','-'),':','-'),'.','-');
DECLARE #Content XML=
(
SELECT [Artikelnummer],[Menge] FROM inserted WHERE [Lagerort]='SHUT1' FOR XML AUTO,ELEMENTS
);
DECLARE #Cmd VARCHAR(4000) = 'Echo "' + CAST(#Content AS VARCHAR(MAX)) + '" >>"c:\temp\' + #FileName + '.xml"' ;
PRINT #cmd;
EXEC xp_cmdshell #Cmd ;
END
END;
This might better be done with BCP.
UPDATE Your comment...
First you should check, if this works at all:
DECLARE #FileName VARCHAR(255) =REPLACE(REPLACE(REPLACE(SYSUTCDATETIME(),' ','-'),':','-'),'.','-');
DECLARE #Content XML=
(
SELECT TOP 5 * FROM sys.objects FOR XML AUTO,ELEMENTS
);
DECLARE #Cmd VARCHAR(4000) = 'Echo "' + CAST(#Content AS VARCHAR(MAX)) + '" >>"c:\temp\' + #FileName + '.xml"' ;
PRINT #cmd;
EXEC xp_cmdshell #Cmd ;
If you find no file in c:\temp\: Are you aware, that SQL-Server will always write in its own context? Might be, that you are awaiting a file in your local c-drive, but the file is written to the Server's machine acutally.
If this works isolatedly, it should work within a trigger too. You might pack the call into BEGIN TRY ... END TRY and add an appropriate CATCH block.
So okay, the "simple" trigger could be really a problem. Now I have this idea:
(one more info: time stamp is not inserted into table "Lagerverwaltung" when a new row is inserted)
Pseudo Code on:
Trigger on Table "Lagerverwaltung"
Check if the storage place(s) is "SHUT1"
If "yes"
DECLARE #FileName VARCHAR(255) =REPLACE(REPLACE(REPLACE(SYSUTCDATETIME(),' ','-'),':','-'),'.','-');
create a new table with name dbo + '.' + #filename
Insert all the data (inserted) + row(SYSUTCDATETIME()) AS TimeStamp where 'Lagerort' = 'SHUT1' into new table named 'dbo.' + #filename
DECLARE #Cmd varchar(4000) = 'bcp "select [Artikelnummer],[Menge],[TimeStamp] FROM [wwsbautest].[dbo].#filename WHERE [Lagerort]=''SHUT1'' AND [Menge] > ''0'' FOR XML AUTO, ELEMENTS" queryout "C:\temp\' + #FileName + '.xml" -c -T';
EXEC xp_cmdshell #Cmd;
Drop table dbo.#filename;
Could somthing like that work?

Using BCP and xp_cmdshell with T-SQL inside SSMS. "The syntax of the command is incorrect"

So, I am playing around with BCP to get to know it better, and ran into an issue I am having trouble figuring out. I am getting an error, "The Syntax of the command is incorrect".
I have tested the complete file path which is building correctly, and the select query by itself, which is completing correctly. Any thoughts?
The code I am using is:
DECLARE #fileName varchar(128)
DECLARE #filePath varchar(128)
DECLARE #completeFilePath varchar(128)
DECLARE #sqlCmd varchar(4000)
DECLARE #BCPSwitches VARCHAR(64)
SET #filePath = 'xxxxxx'
SELECT TOP 5 [EMP]
,[SSNO]
,[NAME]
,[STREET]
INTO #ParticipantIdentifiers
FROM xxxxxxxxx
SET #BCPSwitches = '-w -T -t |'
SET #fileName = 'xxxxx.txt'
SET #completeFilePath = #filePath + #fileName
SET #sqlCmd = 'bcp "SELECT * FROM #ParticipantIdentifiers" queryout "'+ #completeFilePath + '" ' + #BCPSwitches
EXEC DemoDB..xp_cmdshell #sqlCmd
I think the terminator "|" after -t (in the #BCPSwitches) needs to be enclosed in quotes as well since the shell might be interpreting this as a output pipe.

Exporting XML Data to mutiple files but retain structure

I have been searching on the net for the last couple of days and unfortunately cannot find quite what I am looking for. I have a SQL Server 2012 table that contains 2 columns, one is PurchaseOrder DataType varchar(10) the other is Data with a DataType of XML. Currently what is happening ever few hours a stored procedure is run to check a number of table for a value and then create a PurchaseOrder in the desired XML format. This has been achieved and validated by the company that I am going to be sending the data to. The issue I now have is I want to create a SSIS package that looks at this table and creates multiple xml files with the contents of the Data field "not putting the contents in to one long line" and then using the PurchaseOrder field for the file name. I have found various part solutions e.g. using a Script task as there is no native XML Destination in SSIS but struggling and being quite new to SSIS not getting anywhere fast. Can anyone offer any help, guidance, youtube links or even a part way there package.
Thanks P
Further to the above question I have tried to go about it using the bcp command, below is the following code that works great just looking at the top 1 record
DECLARE #fileName VARCHAR(50)
DECLARE #sqlStr VARCHAR(1000)
DECLARE #sqlCmd VARCHAR(1000)
SET #fileName = 'C:\Temp\test.xml'
SET #sqlStr = 'select TOP 1 Data from DatabaseName.dbo.OutputXML'
SET #sqlCmd = 'bcp "' + #sqlStr + '" queryout ' + #fileName + '
-w -T -S Server\Instance'
EXEC xp_cmdshell #sqlCmd
What I have then done is add this in to a cursor, which again works to a point, it creates my files, using the purchaseorder as the file name and outputs the relevant information but it no longer holds the proper xml format, it goes back to looking like a string with none of the original formatting, is this because I am imbedding it in the cursor?? Below is the code that I am using
DECLARE #fileName VARCHAR(50)
DECLARE #sqlStr VARCHAR(1000)
DECLARE #sqlCmd VARCHAR(1000)
DECLARE xml_cursor CURSOR FOR
SELECT PurchaseOrder from DatabaseName.dbo.OutputXML
OPEN xml_cursor
FETCH NEXT FROM xml_cursor INTO #fileName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #fileName = 'C:\Temp\'+#fileName+'.xml'
SET #sqlStr = 'select Data from DatabaseName.dbo.OutputXML'
SET #sqlCmd = 'bcp "' + #sqlStr + '" queryout ' + #fileName + '
-w -T -S Server\Instance'
EXEC xp_cmdshell #sqlCmd
FETCH NEXT FROM xml_cursor into #fileName
END
CLOSE xml_cursor
DEALLOCATE xml_cursor
Since bcp is a command line utility it does not know about your cursor. You can only change the parameters passed. You already pass the #filename from the cursor, you will also need to filter your query. Below is how to fix your problem but it is far from a great solution, it will be quite slow. I don't know what your key is called, so I called it SomeKey
DECLARE #fileName VARCHAR(50)
DECLARE #sqlStr VARCHAR(1000)
DECLARE #sqlCmd VARCHAR(1000)
DECLARE #SomeKey VARCHAR(100) --Put your key datatype here
DECLARE xml_cursor CURSOR FOR
-- replace SomeKey with your key
SELECT SomeKey,PurchaseOrder FROM DatabaseName.dbo.OutputXML
OPEN xml_cursor
FETCH NEXT FROM xml_cursor INTO #SomeKey,#fileName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #fileName = 'C:\Temp\' + #filename + '.xml'
SET #sqlStr = 'SELECT Data FROM DatabaseName.dbo.OutputXML WHERE SomeKey = ''' + #SomeKey +''''
SET #sqlCmd = 'bcp "' + #sqlStr + '" queryout ' + #fileName + '-w -T -S Server\Instance'
EXEC xp_cmdshell #sqlCmd
FETCH NEXT FROM xml_cursor into #SomeKey,#fileName
END
CLOSE xml_cursor
DEALLOCATE xml_cursor

Resources