I am trying to run the following commands to generate a file and populate the file with varchar(MAX) amount of data. Here is the issue, when I try to run the code it creates the files but they are empty. I know the #classString variable has data in it. Is there a string enclosing sequence I can wrap around the #classString to delimit it? I am trying to generate a script so I am assuming the #classString contains characters that are interfering with the file write.
SET #sqlString = 'echo off > ' + #FilePath + '\' + #table_name + '.cs"'
exec xp_cmdshell #sqlString
SET #sqlString = 'echo ' + #classString + ' >> ' + #FilePath + '\' + #table_name + '.cs"'
exec xp_cmdshell #sqlString
There is no easy way to delimit or quote the whole string, instead you need to escape any shell metacharacters within it using the ^ symbol. For example:
SET #classString = (SELECT REPLACE(#classString, '>', '^>'))
SET #classString = (SELECT REPLACE(#classString, '&', '^&'))
...and so on for any cmdshell metacharacters that may feature in your string.
Related
I created the below stored procedure in sql server that requires 3 parameters: Date, URL, & Table Name:
ALTER PROCEDURE [stg].[usp_Delete_Data]
(#DateLookBack date,
#siteUrl nvarchar(100),
#tableName SYSNAME)
AS
BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']') +
'WHERE date = ' + FORMAT(#DateLookBack, 'yyyyMMdd') +
'AND siteUrl = ' + #siteUrl
EXEC sp_executesql #Sql
END
When I pass in a url, like 'https://stackoverflow.com', I get an error message:
Incorrect syntax near 'https:'
How do I format the url string so that it can pass into the query successfully?
I'd strongly advise against this method. Having so many tables of the same structure that it requires a single procedure where the table name is dynamic is a code smell in itself.
If you must use dynamic sql though, at least use parameters as much as possible and only inject your table name, i.e.
SET #sql = CONCAT(N'DELETE FROM [stg].' QUOTENAME(#tableName),
' WHERE Date = #Date AND SiteUrl = #SiteUrl;');
EXECUTE sp_executesql #sql, N'#Date date, #SiteUrl nvarchar(100)', #date, #SiteUrl;
To find such issue, all you need is to PRINT the query before you use it! You could examine the query which is executed, if you printed it first.
Replace the commend Exec sp_executesql #Sql with the command PRINT #Sql and examine the query you get.
In your case, after you do it, then when you execute the procedure using the following command, then I can see all the issues.
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
The printed text which we get is: DELETE FROM [stg].[c]WHERE date = 20220227and siteUrl = https://stackoverflow.com
Now we can go over the errors (yes there are multiple errors here) one by one
(1) Notice that the 'WHERE date = ' missing a space before the "where" which might combine the word "where" with the table name that comes before it. You need to add space like ' WHERE date = '
same with the part after the and siteUrl - missing space before the and
(2) Notice this part: siteUrl = https://stackoverflow.com. in the query you are building you do not have quotation marks around the text of the URL => this lead to the error message.
instead of 'and siteUrl = ' + #siteUrl it should be: 'and siteUrl = ''' + #siteUrl + ''''
(3) same issue you have with the date - you do not have quotation marks around the text of the date
instead of ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd') it should be ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
So, after adding these fixes, you get the following SP (I use PRING instead of execute but you can change this back)
CREATE OR ALTER PROCEDURE [usp_Delete_Data] (
#DateLookBack date,#siteUrl nvarchar(100), #tableName SYSNAME
) AS BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']')
--+ ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd')
+ ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
+ ' and siteUrl = ''' + #siteUrl + ''''
--+ 'and siteUrl = ' + #siteUrl
PRINT #Sql
--Exec sp_executesql #Sql
END
and now if I execute the same query
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
It will print something that looks like:
DELETE FROM [stg].[c] WHERE date = '20220227'and siteUrl = 'https://stackoverflow.com'
BUT! NOW WE CAN GO TO THE MOST PROBLEMATIC ISSUE! Your procedure is open to SQL Injection! You should NOT use such code.
You should use parameters whenever you can when you use sp_executesql and not combine text text. Read the documentation of sp_executesql on how to use parameters as input: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql
I need to copy certain file from a folder A to a folder B, but I need to copy only file based on a condition. The name of the file must start with the same value as a variable I have in my stored procedure.
Here is what I've got at the moment:
DECLARE #SQLFile VARCHAR(1024)
DECLARE #MessageId INT = 3 --copy all the files from the source folder that start with this variable
DECLARE #SourceFolderPath VARCHAR(1024)
DECLARE #DestinationFolderPath VARCHAR(1024)
SET #DestinationFolderPath = '\\mydestination'
SET #SourceFolderPath = '\\mysource'
SET #SQLFile = ' COPY /Y ' + #SourceFolderPath + ' /B ' + #DestinationFolderPath
EXEC master..xp_cmdshell #SQLFile
With this code I copy all the files but I don't know if there is a way to integrate the condition of beginning of name.
Thanks
I'm guessing a simple file glob will do what you want. But as people said in the comments using xp_cmdshell can create all kinds of security issues if used where untrusted data is kicking about. For this reason it is also often blocked by SQL Server security policy.
DECLARE #SQLFile VARCHAR(1024)
DECLARE #MessageId INT = 3 --copy all the files from the source folder that start with this variable
DECLARE #SourceFolderPath VARCHAR(1024)
DECLARE #DestinationFolderPath VARCHAR(1024)
SET #DestinationFolderPath = '\\mydestination'
SET #SourceFolderPath = '\\mysource'
SET #SQLFile = ' COPY /Y ' + #SourceFolderPath + '\' + CAST(#MessageID AS varchar(max)) + '* /B ' + #DestinationFolderPath
EXEC master..xp_cmdshell #SQLFile
Below is my code which is printing my sql result to text file.
My problem is : how to create new text file for each execution, instead of append result to same text file already created?
I am trying to add >> but it only append result in the same text.
need help please, it not the duplicate question because, the old question show how to write result in the same text file but for my problem i need to create new one, and don't want to overwrite the old text file.
Declare #fn varchar(8000) = 'C:\Tmp\log\out.txt';
Declare #cmd varchar(8000);
DECLARE #viewObjectIds TABLE (object_id INT);
INSERT INTO #viewObjectIds
SELECT o.object_id
FROM sys.objects AS o
WHERE o.type = 'V';
DECLARE view_cursor CURSOR FAST_FORWARD FOR
SELECT object_id FROM #viewObjectIds;
OPEN view_cursor;
FETCH NEXT FROM view_cursor INTO #object_id;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #command =
'EXECUTE sp_refreshview '''
+ QUOTENAME(OBJECT_SCHEMA_NAME(#object_id)) + '.' + QUOTENAME(OBJECT_NAME(#object_id))
+ ''';';
PRINT #command;
SELECT #cmd = 'echo '+ #command + ' >> '+ #fn + '' ;
exec xp_cmdshell #cmd
FETCH NEXT FROM view_cursor INTO #object_id;
END
You could concat CURRENT_TIMESTAMP onto the out.txt filename. Simple solution that will create a new file for every execution.
EDIT:
Declare #fn varchar(8000) = 'C:\Tmp\log\' + convert(varchar(25), current_timestamp, 120) + 'out.txt';
I'm trying to create a txt file in a shared folder using xp_cmdshell in SQL Server.
The code works perfectly, but I need to begin the text with:
"<0600 ..."
So when I write " < " or " > " in the query, I get an error:
The system cannot find the file specified.
Here's an example of my code:
declare #Text as nvarchar(150) declare #Cmd as nvarchar(100) set #Text = '<0600 /SERIAL= ....>' set #Cmd ='echo ' + #Text + ' > C:\Test.txt' execute ..xp_CmdShell #Cmd
So, how can I create the text file with these characters?
Escape the redirection symbols (< and >) with ^
declare #Text as nvarchar(150)
declare #Cmd as nvarchar(100)
set #Text = '^<0600 /SERIAL= ....^>'
set #Cmd ='echo ' + #Text + ' > C:\Test.txt'
execute ..xp_CmdShell #Cmd
http://www.robvanderwoude.com/escapechars.php
My question is in my title, I have defined a stored procedure with the following
CREATE PROCEDURE [dbo].[sp_doStuff]
#path CHAR(256), #databaseName sysname, #backupType CHAR(1)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sqlCommand NVARCHAR(1000)
DECLARE #dateTime NVARCHAR(20)
SELECT #dateTime = REPLACE(CONVERT(VARCHAR, GETDATE(),111),'/','') +
REPLACE(CONVERT(VARCHAR, GETDATE(),108),':','')
IF #backupType = 'F'
SET #sqlCommand = 'BACKUP DATABASE ' + #databaseName +
' TO DISK = ' + #path + #databaseName + '_Full_' + #dateTime + '.BAK'''
IF #backupType = 'D'
SET #sqlCommand = 'BACKUP DATABASE ' + #databaseName +
' TO DISK = ' + #path + #databaseName + '_Diff_' + #dateTime + '.BAK'' WITH DIFFERENTIAL'
IF #backupType = 'L'
SET #sqlCommand = 'BACKUP LOG ' + #databaseName +
' TO DISK = ' + #path + #databaseName + '_Log_' + #dateTime + '.TRN'''
EXECUTE sp_executesql #sqlCommand
END
When I want to run the following command:
[dbo].[sp_doStuff] 'D:\FolderName\', 'MyDatabase', 'F';
It gives me this error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'D:'.
Msg 105, Level 15, State 1, Line 1
Unclosed quotation mark after the character string ''.
Does anyone have a clue why this gives errors? I can make it work by hard coding the path into the procedure, but I want to be able to pass it in a a parameter.
Try
' TO DISK = ''' + #path + #databaseName
etc...
It is not the issue of parameter. you are making wrong execute statement that uses single quote and you have not escaped that one..
you can escape single quote using two single quotes (NOT double quote). If a character string enclosed in single quotation marks contains an embedded quotation mark, represent the embedded single quotation mark with two single quotation marks.
e.g.
USE AdventureWorks
GO
SELECT *
FROM Person.Address
WHERE City = 'Villeneuve-d''Ascq'
GO
Ref:
Escape Character in SQL
SQL SERVER – How to Escape Single Quotes – Fix: Error: 105 Unclosed quotation mark after the character string ‘