String concatenation in SQL doesn't work - sql

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.

Related

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;

How to use a variable in Openrowset command

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 :

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;

Create SQL Server stored procedure with stock data

I am trying to turn some code I have from SQL Server into a stored procedure with parameters that I can pass through but I am not sure how to do this. I want the 4 letter stock symbol of the URL to be a variable so that I can pass through different symbols, I also need this code to work as a stored procedure.
GOOG is where I need the variable.
http://finance.yahoo.com/webservice/v1/symbols/GOOG/quote'
--RSS FEED
DECLARE #docHandle INT;
DECLARE #xmlData XML;
DECLARE #URL NVARCHAR(255);
DECLARE #file NVARCHAR(255);
DECLARE #cmd NVARCHAR(255);
DECLARE #sql NVARCHAR(255);
DECLARE #tXML TABLE(data XML);
SET #URL = 'http://finance.yahoo.com/webservice/v1/symbols/GLUU/quote';
SET #file = 'c:\temp\quotes.xml';
-- Downloading the data
SET #cmd = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell (new-object System.Net.WebClient).DownloadFile( ''' + #URL + ''',''' + #file + ''' )'
EXEC master.dbo.xp_cmdshell #cmd, no_output
-- Loading the Downloaded File into the XML variable
SET #sql = 'SELECT BulkColumn FROM OPENROWSET( BULK ''' + #file + ''', SINGLE_BLOB ) AS a'
INSERT #tXML EXEC(#sql);
SELECT #xmlData = data from #tXML
-- Preparing the Relational Table from the XML variable
EXEC sp_xml_preparedocument #docHandle OUTPUT, #xmlData;
INSERT INTO tblstockdata ([Name], [Price], [Symbol], [TS], [Type], [Volume])
SELECT * FROM OPENXML(#docHandle, N'//list/resources/resource')
WITH ( Name VARCHAR(10) 'field[#name="name"]',
Price VARCHAR(10) 'field[#name="price"]',
Symbol VARCHAR(10) 'field[#name="symbol"]',
TS VARCHAR(10) 'field[#name="ts"]',
Type VARCHAR(10) 'field[#name="type"]',
Volume VARCHAR(10) 'field[#name="volume"]');
EXEC sp_xml_removedocument #docHandle;
Thanks!
:)
You have working SQL, which is the tough part. Now bracket your working SQL with
CREATE PROCEDURE <schema>.<Name>(
#param <type>
) as begin
and
end
and you should be good to go. For starters you can use dbo as the value of <schema> until you need to use a non-default schema. It is recommended that you not use the prefix "sp" or "xp" for your procedure name as these are used to identify system and extended procedures by SQL Server.
If you need additional parameters they can be added to the parameter list using a comma as the delimiter.
Below is a stored procedure example gleaned from your code that takes the needed symbol parameter. Here, I used the XML data type methods rather than sp_xml_preparedocument. If multiple users might call this stored procedure at the same time, I suggest you generate a unique name for the file an delete afterwards. You might consider a CLR stored procedure to avoid both the temporary file and OPENROWSET ugliness.
CREATE PROC dbo.usp_GetEquityQuote
#symbol varchar(10)
AS
DECLARE #URL NVARCHAR(255);
DECLARE #file NVARCHAR(255);
DECLARE #cmd NVARCHAR(255);
DECLARE #sql NVARCHAR(255);
DECLARE #tXML TABLE(data XML);
SET #URL = 'http://finance.yahoo.com/webservice/v1/symbols/' + #symbol + '/quote';
SET #file = 'c:\temp\quotes.xml';
-- Downloading the data
SET #cmd = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell (new-object System.Net.WebClient).DownloadFile( ''' + #URL + ''',''' + #file + ''' )';
EXEC master.dbo.xp_cmdshell #cmd, no_output;
-- Loading the Downloaded File into the XML variable
SET #sql = 'SELECT BulkColumn FROM OPENROWSET( BULK ''' + #file + ''', SINGLE_BLOB ) AS a';
INSERT #tXML EXEC(#sql);
SELECT data from #tXML ;
SELECT
resources.resource.value('field[#name="name"][1]', 'varchar(10)') AS name
,resources.resource.value('field[#name="price"][1]', 'decimal(18,4)') AS price
,resources.resource.value('field[#name="symbol"][1]', 'varchar(10)') AS symbol
,resources.resource.value('field[#name="ts"][1]', 'bigint') AS ts
,resources.resource.value('field[#name="type"][1]', 'varchar(10)') AS type
,resources.resource.value('field[#name="volume"][1]', 'bigint') AS volume
FROM (SELECT data FROM #tXML) AS tXML(data)
CROSS APPLY data.nodes('/list/resources/resource') AS resources(resource);

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