How to use a variable in Openrowset command - sql

I am trying to use a variable filepath in a SQL Openrowset command. I'm aware that it can't explicitly accept a variable and that I need to make use of dynamic SQL.
What currently works -
SELECT #file_stream = CAST(bulkcolumn AS VARBINARY(MAX))
FROM OPENROWSET(BULK 'C:\Temp\print4.pdf', SINGLE_BLOB) AS x
However if I try to use my variable filepath
declare #file_stream VARBINARY(MAX)
declare #filePath NVARCHAR(128)
set #filePath = 'C:\Temp\print4.pdf'
set #command = N'SELECT #file_stream = CAST(bulkcolumn AS varbinary(MAX))
from OPENROWSET(BULK ' + #filePath + ',
SINGLE_BLOB) ROW_SET'
EXEC sp_executesql #command, #filePath, #file_stream;
I get the error 'Msg 137, Level 15, State 2, Line 15
Must declare the scalar variable "#filePath".'
I'm sure this is an issue of syntax but haven't been able to figure out how it should be formatted yet.

Change your script like below.
DECLARE #file_stream VARBINARY(MAX)
DECLARE #command nvarchar(1000)
DECLARE #filePath NVARCHAR(128)
set #filePath = 'C:\Temp\print4.pdf'
set #command = N'SELECT #file_stream1 = CAST(bulkcolumn AS varbinary(MAX))
from OPENROWSET(BULK ''' + #filePath + ''',
SINGLE_BLOB) ROW_SET'
EXEC sp_executesql #command, N'#file_stream1 VARBINARY(MAX) OUTPUT',#file_stream1 =#file_stream OUTPUT
select #file_stream
Sample Output :

Related

How to use a variable in Openrowset command With SQL Commands

I want to update database from a .sql file which contain some commands like update and edit and delete.
I try hard to pass the .sql file to the procedure to make it run.
This is my code which only shows me the file instead of running it:
DECLARE #filePath nvarchar(1000)
DECLARE #command nvarchar(1000)
DECLARE #query nvarchar(1000)
SET #filePath = 'd:\amz\update_price001.sql'
SET #command = '(SELECT * FROM OPENROWSET(BULK '''+#filePath+''', SINGLE_CLOB) AS Contents)'
SELECT #command
SET #query = #command
EXEC sp_executesql #query
This is the result of the select #command:
(SELECT * FROM OPENROWSET(BULK 'd:\amz\update_price001.sql', SINGLE_CLOB) AS Contents)
but the result of the EXEC sp_executesql #query is the filecontent - not the execution result.

Stored Procedure to Import XML into SQL Server

I'm trying to import XMLs into SQL Server. If I print the below #command, I can copy and paste into SSMS and the code runs perfectly. However, I get the following error if I try to run this as an sp.
exec etl.import_xml 'c:\xml_file.xml'
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#stream".
ALTER PROCEDURE etl.import_xml (
#file_name VARCHAR(1000)
) AS
BEGIN
DECLARE #command NVARCHAR(1000)
DECLARE #stream VARCHAR(MAX)
SET #command = N'SELECT #stream = CAST(BulkColumn AS VARCHAR(MAX))
FROM OPENROWSET(BULK ''' + #file_name + ''', SINGLE_BLOB) AS x;'
--EXEC sp_executesql #command, N'#file_stream_out VARCHAR(MAX) OUTPUT', #stream_out = #stream OUTPUT
EXECUTE(#command)
SET #stream = dbo.strip_xmlns(#stream)
UPDATE swf.etl.raw_data
SET xml_string = CONVERT(XML, #stream)
WHERE xml_file_name = #file_name
END
As per Dale K, I need to declare everything within the command string. Obviously there are still issues with SQL injection, however no user will have access to this proc and will only be run on an automation server.
ALTER PROCEDURE etl.import_xml (
#file_name VARCHAR(1000)
) AS
BEGIN
DECLARE #command NVARCHAR(1000)
DECLARE #stream VARCHAR(MAX)
SET #command = N'DECLARE #stream VARCHAR(MAX) SELECT #stream = CAST(BulkColumn AS VARCHAR(MAX))
FROM OPENROWSET(BULK ''' + #file_name + ''', SINGLE_BLOB) AS x;
SET #stream = dbo.strip_xmlns(#stream)
UPDATE swf.etl.raw_data
SET xml_string = CONVERT(XML, #stream)
WHERE xml_file_name = ''' + #file_name + '''
'
EXECUTE(#command)
END
Here is how to do it with an XML file name as a parameter.
SQL
DECLARE #xml XML
, #sql NVARCHAR(MAX)
, #fileName VARCHAR(256) = 'e:\Temp\Diego.xml';
SET #sql = N'SELECT #xmlOut = XmlDoc FROM OPENROWSET (BULK ' + QUOTENAME(#fileName,NCHAR(39)) + ', SINGLE_BLOB) AS Tab(XmlDoc)';
EXEC sys.sp_executesql #sql, N'#xmlOut XML OUTPUT', #xmlOut = #xml OUTPUT;
SELECT #xml;

String concatenation in SQL doesn't work

I am wondering why the following doesn't work:
INSERT INTO #Data2 (FileName,Field)
SELECT #FileName as FileName, * FROM OPENROWSET(BULK '\\serverpath\' + #FileName , SINGLE_CLOB) AS Contents
I tried also the second approach but with this one I get the error message that the variable isn't declared:
declare #path nvarchar(255) = 'SELECT #FileName as FileName, * FROM OPENROWSET(BULK ''\\serverpath\' + #FileName + ''', SINGLE_CLOB) AS Contents'
INSERT INTO #Data2 (FileName,Field)
EXEC(#path)
Can somebody help?
Thanks
You can not pass #FileName as FileName using exec, but you can using sp_executesql -- but you still can not pass #FileName as part of openrowset():
declare #path nvarchar(4000) = N'
select #FileName as FileName, *
from openrowset(bulk ''\\serverpath\' + #FileName + '''
, single_clob) as Contents'
insert into #Data2 (FileName,Field)
exec sp_executesql, N'#FileName nvarchar(1024))',#FileName
Or directly concatenating it like you are for the bulk source:
declare #path nvarchar(4000) = N'
select '+quotename(#FileName,'''')+' as FileName, *
from openrowset(bulk '+quotename('\\serverpath\'+#FileName,'''')+'
, single_clob) as Contents'
insert into #Data2 (FileName,Field)
exec sp_executesql #path
reference:
The curse and blessings of dynamic SQL - Erland Sommarskog
sp_executesql
You cannot use OPENROWSET with a variable path. Check this:
--This works
DECLARE #Data2 TABLE(Field VARBINARY(MAX));
INSERT INTO #Data2 (Field)
SELECT * FROM OPENROWSET(BULK 'F:\Privat\StackOverflow\test.xml' , SINGLE_BLOB) AS Contents;
SELECT CAST(Field AS NVARCHAR(MAX)) FROM #Data2;
--This breaks at syntax check
DECLARE #FileName AS VARCHAR(1000)='F:\Privat\StackOverflow\test.xml';
INSERT INTO #Data2 (Field)
SELECT * FROM OPENROWSET(BULK #FileName , SINGLE_BLOB) AS Contents;
SELECT CAST(Field AS NVARCHAR(MAX)) FROM #Data2;
--This works, but needs a physically created table. Your table variable is out of scope within the EXEC-execution
CREATE TABLE Data2(Field VARBINARY(MAX));
DECLARE #FileName AS VARCHAR(1000)='F:\Privat\StackOverflow\test.xml';
DECLARE #cmd VARCHAR(MAX)='INSERT INTO Data2(Field) SELECT * FROM OPENROWSET(BULK ''' + #FileName + ''', SINGLE_BLOB) AS Contents;'
EXEC(#cmd);
SELECT * FROM Data2;
GO
DROP TABLE Data2;
Instead of the physically created table you might use an output parameter.

How to pass a string variable in BULK LOAD command in SQL

I want to pass the file name as a variable in SQL BULK load. But I am getting a syntax error. If someone can help that will be great. Below is the code that I wrote.
DECLARE #XML AS XML,#File VARCHAR(200)
SELECT #File='C:\xyz.xml'
SELECT #XML= CONVERT(XML, BulkColumn) FROM OPENROWSET(BULK #File, SINGLE_BLOB) AS x
I can not hardcode #File like BULK 'C:\xyz.xml' as the file name will change frequently.
You can't parametrise it. So use dynanic SQL
DECLARE #XML AS XML, #File VARCHAR(200);
DECLARE #SQL nvarchar(max);
SET #File='C:\xyz.xml';
SET #SQL = 'SELECT #XML= CONVERT(XML, BulkColumn) FROM OPENROWSET(BULK ''' + #File + ''', SINGLE_BLOB) AS x';
EXEC sys.sp_executesql #SQL, N'#XML xml', #XML;
Editing your answer as it was not giving #XML value
DECLARE #XML AS XML, #File VARCHAR(200);
DECLARE #SQL nvarchar(max);
SET #File='C:\xyz.xml';
SET #SQL = 'SELECT #XML_OUT= CONVERT(XML, BulkColumn) FROM OPENROWSET(BULK ''' + #File + ''', SINGLE_BLOB) AS x';
EXEC sys.sp_executesql #SQL, N'#XML xml OUT', #XML_OUT=#XML OUTPUT;

T-SQL, Load XML data into a local variable

I would like to know, how can I load the XML content from an arbitrary file into a local variable?
This works for a fixed file:
DECLARE #xml XML
SET #xml =
(
SELECT *
FROM OPENROWSET(BULK 'C:\data.xml', SINGLE_BLOB) AS data
)
However, I would like to load the data from any arbitrary file.
This does not work (as BULK seems to only support String arguments)
DECLARE #file NVARCHAR(MAX) = 'C:\data.xml'
DECLARE #xml XML
SET #xml =
(
SELECT *
FROM OPENROWSET(BULK #file, SINGLE_BLOB) AS data
)
I've also tried the following (without success, as the local variable (#xml) seems to be out of scope when the EXEC is performed):
DECLARE #file NVARCHAR(MAX) = 'C:\data.xml'
DECLARE #xml XML
DECLARE #bulk NVARCHAR(MAX) = 'SET #xml = (SELECT * FROM OPENROWSET(BULK ''' + #file + ''', SINGLE_BLOB) AS data)'
EXEC (#bulk)
I'm guessing I need to use a temporary table, but how?
Found a solution:
DECLARE #results table (result XML)
DECLARE #sqlstmt NVARCHAR(MAX)
SET #sqlstmt= 'SELECT * FROM OPENROWSET ( BULK ''' + #file + ''', SINGLE_CLOB) AS xmlData'
INSERT INTO #results EXEC (#sqlstmt)
SELECT #xml = result FROM #results
you can also use sp_executesql:
declare #stmt nvarchar(max), #xml xml
select #stmt = '
set #xml = (select * from openrowset(bulk ''' + #file + ''', single_clob) as data)
'
exec dbo.sp_executesql
#stmt = #stmt,
#params = '#xml xml output',
#xml = #xml output