How to create text file using sql script with text "|" - sql

if i run below script without char "|" it working but when i am adding char "|" it is not working
how to add char "|" using sql script to text file ?
DECLARE #Text AS VARCHAR(100)
DECLARE #Cmd AS VARCHAR(100)
SET #Text = 'Hello world| '
SET #Cmd ='echo ' + #Text + ' > C:\AppTextFile.txt'
EXECUTE Master.dbo.xp_CmdShell #Cmd
thanks

The pipe character has a special meaning in batch commands, so it must be escaped using the caret character. This should work:
DECLARE #Text AS VARCHAR(100)
DECLARE #Cmd AS VARCHAR(100)
SET #Text = 'Hello world^| '
SET #Cmd ='echo ' + #Text + ' > C:\AppTextFile.txt'
EXECUTE Master.dbo.xp_CmdShell #Cmd
Although this is really not a good way to write data to a text file: usually SQL Server should not have permission to write to the root of the C: drive, and xp_cmdshell is disabled by default. I suggest you look at alternatives like sqlcmd.exe, bcp.exe or a small script in your preferred language (PowerShell, Perl, Python, whatever).
It is generally much easier, safer and more flexible to query data from SQL Server than it is to push it out from the server side. In your specific case, it looks like you want to write out a delimited file, and bcp.exe is intended for that purpose.

Other way to do this
DECLARE #File varchar(300) = 'c:\Temp\out.txt'
DECLARE #Text varchar(8000) = 'Sample text'
DECLARE #OLE INT
DECLARE #FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', #OLE OUT
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 1
EXECUTE sp_OAMethod #FileID, 'WriteLine', Null, #Text
EXECUTE sp_OADestroy #FileID
EXECUTE sp_OADestroy #OLE
Check for errors using SP result
EXECUTE #result = sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 1
if #result<>0 GOTO ON_ERROR
Haven't found the way to read error message though

wrap it with two pairs of single quotes,
DECLARE #Text AS VARCHAR(100)
DECLARE #Cmd AS VARCHAR(100)
SET #Text = '''Hello world| '''
SET #Cmd ='echo ' + #Text + ' > C:\AppTextFile.txt'
EXECUTE Master.dbo.xp_CmdShell #Cmd

Related

Check Existing File using xp_cmdshell in SQL and return a value in cmdshell

I am trying to create a file using the SP - MSSQL. before creating a file i want to check Whether the file exist . IF Exist i want to replace a new one or else create a new file. Want to return a value while executing the cmdshell in sql.
DECLARE #Text AS VARCHAR(100)
DECLARE #Cmd AS VARCHAR(100)
DECLARE #exstFile AS VARCHAR(100)
set #cmd = 'IF EXIST Z:\AppTextFile.txt (ECHO 1) ELSE (ECHO 0)'
EXEC #cmd = xp_cmdshell #cmd
select #cmd datum
An alternative way for to check files existence could be to use xp_FileExist:
DECLARE #Exists INT;
EXEC master..xp_FileExist N'U:\SSIS\Test.txt', #Exists OUTPUT
select #Exists

SQL - Create XML - How to set Unicode UTF-8

I have a problem with creating an XML file from inside a SQL PROCEDURE.
The XMLs get created and placed in the correct folder. Although when I open the file in XMLSpy, it says the following error:
Your file contains 3 character(s) that should not be present in a file using the Unicode UTF-8 encoding...
The offending characters are è (0xE8), ü (0xFC), é (0xE9)
When I open the XML file in Notepad++ and check for encoding (via menu Encoding on top), it says it is in ANSI and not in UTF-8.
So my question is: How do I get it to turn into UTF-8? Any suggestions?
The code of my procedure can be found below:
#File VARCHAR(2000) // parameter
AS
BEGIN
DECLARE #OLE INT
DECLARE #FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', #OLE OUT
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 1
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
EXECUTE sp_OAMethod #FileID, 'WriteLine', Null, #Text
EXECUTE sp_OADestroy #FileID
EXECUTE sp_OADestroy #OLE
END
EDIT 1
Changed my code, exporting to ASCII instead of Unicode (as suggested below by Wolf), but this didn't help too. But here is that part of code:
DECLARE #OLE INT
DECLARE #FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', #OLE OUT
EXECUTE sp_OAMethod #OLE, 'CreateTextFile', #FileID OUT, #File, 2, False
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
EXECUTE sp_OAMethod #FileID , 'Write', Null, #Text
EXECUTE sp_OAMethod #FileID , 'Close'
EXECUTE sp_OADestroy #FileID
EXECUTE sp_OADestroy #OLE
END
I found a solution via another way. (don't remember which website I found it)
See code below. This code will export my file in UTF-8-BOM encoding.
#File VARCHAR(2000)
AS
BEGIN
DECLARE #OLE INT
EXECUTE sp_OACreate 'ADODB.Stream', #OLE OUTPUT
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
DECLARE #Converted NVARCHAR(MAX)
SET #Converted = CONVERT(nvarchar(MAX), #Text)
EXECUTE sp_OASetProperty #OLE, 'Type', 2 --1 = binary, 2 = text
EXECUTE sp_OASetProperty #OLE, 'Mode', 3 --0 = not set, 1 read, 2 write, 3 read/write
EXECUTE sp_OASetProperty #OLE, 'Charset', 'UTF-8' --'ISO-8859-1'
EXECUTE sp_OASetProperty #OLE, 'LineSeparator', 'adLF'
EXECUTE sp_OAMethod #OLE, 'Open'
EXECUTE sp_OAMethod #OLE, 'WriteText', NULL, #Converted --text method
--Commit data and close text stream
EXECUTE sp_OAMethod #OLE, 'SaveToFile', NULL, #File, 2 --1 = notexist 2 = overwrite
EXECUTE sp_OAMethod #OLE, 'Close'
EXECUTE sp_OADestroy #OLE
EXECUTE sp_OADestroy #OLE
END
Generally, SQL Server does not support UTF-8 by itself. However, I'm not sure about FSO, maybe it does.
The OpenTextFile documentation states that you can determine the file format, i.e. ASCII or Unicode. Try:
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 0;
This should give you an ASCII file format.

New line char in file using SQL

I'm making some test variable and I insert a new line character into it. When I print it everything is ok, 1 word is below the second one. But when I write the value of this variable into *.txt file the new line character doesn't work.
Here is my example:
DECLARE #cmd varchar(200), #var varchar(200)
SET #var = 'Hello' + CHAR(13) + 'world'
SET #cmd = 'echo ' + #var + ' > E:\s.txt'
print #cmd
EXEC master..xp_cmdshell #cmd
I was trying with DECLARE #NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10) or \r\n instead of this CHAR(13) but no effect :/ Could someone give me small hint about this problem?
I'm using Microsoft SQL Server 2008 R2
Does this work?
DECLARE #cmd varchar(200), #var varchar(200);
SET #var = 'Hello
world';
SET #cmd = 'echo ' + #var + ' > E:\s.txt';
print #cmd;
EXEC master..xp_cmdshell #cmd;
EDIT:
I believe your problem is escaping the new line in the windows shell. Try the escape character '^':
DECLARE #cmd varchar(200), #var varchar(200);
SET #var = 'Hello^
world';
SET #cmd = 'echo ' + #var + ' > E:\s.txt';
print #cmd;
EXEC master..xp_cmdshell #cmd;
Be sure there is no space or other character after the '^'.

Using OUTPUT Parameters within Dynamic SQL within Stored Procedures- Possible?

I have a SP that I have created to check for validations and return an OUTPUT Parameter of 0 (No Error) or 1 (Error). However, I have to run this SP within Dynamic SQL since it will be ran through a loop of different data.
Can I pull the OUTPUT from the SP through the EXEC sp_executesql #SQL?
I can not post the actual code, but I can give an example..
DECLARE
#SQL nVARCHAR(4000),
#SPName VARCHAR(200),
#Parm1 VARCHAR(100),
#Parm2 VARCHAR(100),
#Parm3 VARCHAR(100),
#ParmDefinition nVARCHAR(400),
#Error nVARCHAR(1)
SELECT
#SPName = 'spExample1',
#Parm1 = '000000',
#Parm2 = '111111',
#Parm3 = '#Err=#Error OUTPUT',
SET #SQL = 'EXEC ' + #SPName + ' ' + #Parm1 + ',' + #Parm2 + ',' + #Parm3 + '
SET #ParmDefinition = N'#Err2 nVARCHAR(1) OUTPUT'
EXEC sp_executesql #SQL, #ParmDefinition, #Err2=#Error OUTPUT
The #SQL Variable ends up being:
EXEC spExample1 000000, 111111, #Err=#Error OUTPUT
^^Which works perfectly by itself.
Basically I'm trying to get the OUTPUT through the above code, but when it's ran through Dynamically.
Is this possible or is there another way to do this?
The way things kind of play out in the end appear to be:
EXEC sp_executesql EXEC spExample1 000000, 111111, #Err=#Error OUTPUT, #Err2 nVARCHAR(1) OUTPUT, #Err2=#Error OUTPUT
After looking at that it looks ridiculous, however any help would definitely be appreciated.
Sorry for the delay :D, the following code works perfectly (For N.. output and input parameters) please try this (source):
CREATE PROCEDURE Myproc
#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT
AS
SELECT #parm1OUT='parm 1' + #parm
SELECT #parm2OUT='parm 2' + #parm
GO
DECLARE #SQLString NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #parmIN VARCHAR(10)
DECLARE #parmRET1 VARCHAR(30)
DECLARE #parmRET2 VARCHAR(30)
SET #parmIN=' returned'
SET #SQLString=N'EXEC Myproc #parm,
#parm1OUT OUTPUT, #parm2OUT OUTPUT'
SET #ParmDefinition=N'#parm varchar(10),
#parm1OUT varchar(30) OUTPUT,
#parm2OUT varchar(30) OUTPUT'
EXECUTE sp_executesql
#SQLString,
#ParmDefinition,
#parm=#parmIN,
#parm1OUT=#parmRET1 OUTPUT,#parm2OUT=#parmRET2 OUTPUT
SELECT #parmRET1 AS "parameter 1", #parmRET2 AS "parameter 2"
go
drop procedure Myproc
I haven't tested this in depth, but I did note the following:
When calling stored procedures, you can't mix-and-match named and not-named parameters. So instead of
EXEC sp_executesql #SQL, #ParmDefinition, #Err2=#Error OUTPUT
use
EXEC sp_executesql #SQL, #ParmDefinition, #Error OUTPUT
but, since the output parameter defined for sp_executesql is #Err2, it needs to be
EXEC sp_executesql #SQL, #ParmDefinition, #Err2 OUTPUT
This should work.

Generating XML file from SQL Server 2008

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