Variable should be declared - sql-server

I'm using T-SQL. The goal is to insert multiples files into a database.
If I'm using without a loop, it's working fine.
In the loop, I always get this error:
#InputXML should be declared
My code:
IF OBJECT_ID('TEMPDB..#TEMP_FILES') IS NOT NULL
DROP TABLE #TEMP_FILES
CREATE TABLE #TEMP_FILES
(
FileName VARCHAR(MAX),
DEPTH VARCHAR(MAX),
[FILE] VARCHAR(MAX)
)
INSERT INTO #TEMP_FILES
EXEC master.dbo.xp_DirTree '\\MyServer\MyFolder\',1,1
DELETE FROM #TEMP_FILES WHERE RIGHT(FileName,4) != '.XML'
--
SET QUOTED_IDENTIFIER ON
GO
TRUNCATE Table MyTable2
DECLARE #InputXML XML
DECLARE #FILENAME VARCHAR(MAX),#SQL VARCHAR(MAX)
WHILE EXISTS(SELECT * FROM #TEMP_FILES)
BEGIN
SET #FILENAME = (SELECT TOP 1 FileName FROM #TEMP_FILES)
SET #sql = 'SELECT #InputXML = CAST(x AS XML) FROM OPENROWSET(BULK \\MyServer\MyFolder\'''+ #FILENAME +''', SINGLE_BLOB) AS T(x)
INSERT INTO MyTable2 ([id],[version], [name], [listId], [listCode])
SELECT
product.value(''(#id)[1]'', ''NVARCHAR(10)''),
product.value(''(#version)[1]'', ''NVARCHAR(14)''),
product.value(''(name[1])'', ''NVARCHAR(255)''),
product.value(''(listId[1])'', ''NVARCHAR(9)''),
product.value(''(listCode[1])'', ''NVARCHAR(10)'')
FROM #InputXML.nodes(''xxx/values/value'') AS X(product)'
EXEC(#SQL)
DELETE FROM #TEMP_FILES
WHERE FileName = #FILENAME
END

You need to declare the variable inside the dynamic SQL (which should be nvarchar not varchar). You should also use QUOTENAME to ensure no issues with the filename:
DECLARE #sql nvarchar(max) = N'
DECLARE #InputXML XML;
SELECT #InputXML = CAST(x AS XML) FROM OPENROWSET(BULK ' + QUOTENAME(N'\\MyServer\MyFolder\' + #FILENAME, '''') + N', SINGLE_BLOB) AS T(x)
INSERT INTO MyTable2 ([id],[version], [name], [listId], [listCode])
SELECT
product.value(''(#id)[1]'', ''NVARCHAR(10)''),
product.value(''(#version)[1]'', ''NVARCHAR(14)''),
product.value(''(name[1])'', ''NVARCHAR(255)''),
product.value(''(listId[1])'', ''NVARCHAR(9)''),
product.value(''(listCode[1])'', ''NVARCHAR(10)'')
FROM #InputXML.nodes(''xxx/values/value'') AS X(product)'
I will say though, that I urge you to find another method to load files into SQL Server. Dynamic OPENROWSET, especially from user input, is not advisable. Bulk Insert or BCP may be an option.

Related

Insert data in a SQL Server table when table name, column names and values are given as variables in Insert statement?

I'm trying to create a generic script to copy data from one database to another and I've written this script.
USE TargetDatabase;
DECLARE #SourceDatabase NVARCHAR(100);
DECLARE #TargetDatabase NVARCHAR(100);
DECLARE #SourceTable NVARCHAR(100);
DECLARE #TargetTable NVARCHAR(100);
DECLARE #var NVARCHAR(MAX);
SET #SourceDatabase = 'SourceDB'
SET #TargetDatabase = 'TargetDB'
SET #SourceTable = 'SourceTable'
SET #TargetTable = 'TargetTable'
set #var = (SELECT STRING_AGG (QUOTENAME(COLUMN_NAME), ',') from
#TargetDatabase.INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #TargetTable);
As you can see below, in the INSERT statement I'm giving Table Name, Column Name and Values as a variable. This is where I'm having problems, so basically I don't know how to evaluate these variables #var, #SourceTable, #TargetTable.
INSERT INTO #TargetTable (SELECT #Var)
SELECT * FROM #SourceTable
I'm stuck here and I don't know how to solve this issue. Can any one explain how I can solve this problem?
There are many other ways to run a dynamic query but here is one way you can run your query as per your requirements.
declare #table nvarchar(50)
declare #query nvarchar(500)
set #table = 'Test'
set #query='insert into [' +#table+ '] Select * from [' +#table+ ']';
Exec sp_executesql #query;

Inserting PDFs into an SQL table

So I'm trying to read a bunch of PDFs from a folder into an SQL table, saving them in a varbinary(max) field. This is what I thought would work at first:
CREATE TABLE tempFileName(filnavn VARCHAR(100));
INSERT INTO tempFileName
EXEC xp_cmdshell 'dir /B "C:\temp\Test Folder\"';
--------
DECLARE #path VARCHAR(100) SET #path = 'C:\temp\Test Folder\'
DECLARE #pdf VARBINARY(MAX)
DECLARE #navn varchar(50)
DECLARE #fullpath nvarchar(max)
DECLARE #sql nvarchar(max)
DECLARE c CURSOR FOR
SELECT filnavn
FROM tempFileName
OPEN c
FETCH NEXT FROM c INTO #navn
WHILE(##FETCH_STATUS = 0)
BEGIN
SET #fullpath = #path + #navn
SELECT #pdf = BulkColumn
FROM OPENROWSET(BULK #fullpath, SINGLE_BLOB) AS Document;
--print #sql
INSERT INTO pdftest VALUES(#navn, #pdf)
FETCH NEXT FROM c INTO #navn
END
CLOSE c
DEALLOCATE c
But this doesn't work as it won't allow me to use a variable in this line:
FROM OPENROWSET(BULK #fullpath, SINGLE_BLOB) AS Document;
So I'm pretty sure the trick is to make the whole "select #pdf.." line into a string and then execute it, but I'm not sure how to get the output into a table. I've tried something like this:
SET #fullpath = #path + #navn
SET #sql = 'DECLARE #pdf VARBINARY(MAX) SELECT #pdf = BulkColumn
FROM OPENROWSET(BULK ''' + #fullpath + ''' , SINGLE_BLOB) AS Document;'
--print #sql
--SELECT #pdf, DATALENGTH(#pdf)
--INSERT INTO pdftest VALUES(#navn, #pdf)
EXEC sp_executesql #sql, N'#fil varbinary(max) out', #fil out
But the #fil variable is just empty after this. How do I best go about getting these files into a table?
Why not just skip the variable assignment of the SELECT in your loop and use the OPENROWSET function inside your INSERT? The general idea:
INSERT INTO pdftest SELECT #navn, * FROM OPENROWSET(BULK, 'C:\thefile.txt', SINGLE_BLOB) AS document
And of course turn above into dynamic SQL. I'll probably get a few single-quotes wrong here, but again the general idea:
SET #sql =
'INSERT INTO pdftest
SELECT '' + #navn + '', *
FROM OPENROWSET(BULK, ''' + #fullpath + ''', SINGLE_BLOB) AS document
'

Insert file to SQL Server without front end using stored procedure

I am trying to insert file through SQL. I use following query.
INSERT INTO [dbo].[Attachments] (FileName, FileBinary)
SELECT
'non-date-in-sql-server-column',
BulkColumn
FROM
OPENROWSET(Bulk 'C:\Users\Pictures\Picture.JPG', SINGLE_BLOB) AS BLOB
It's working fine.
I want to write the procedure that take dynamic path. Its giving me error that I cannot take Filebinary in addin. Which is datatype varbinary. What is the best way to do ?
I have done following but its not taking properly binary value.
DECLARE #SQLString NVARCHAR(MAX)
SET #SQLString = 'SELECT ' + '''' +#Filename +'''' + ' AS Name,' + 'FileBinary
FROM OPENROWSET(BULK N''' + #ImagePath + ''',SINGLE_BLOB) AS FileBinary(FileBinary);'
Insert Into Attachments (ApplicantID, FileName, FileBinary)
Values (#ApplicantID, #FileName, Convert(varbinary(max), #SQLString))
Put the Insert statement inside a dynamic query and execute it.
Now your #SQLString will not have the FileBinary value it will have the dynamically framed string . You need to execute it to get the values
DECLARE #SQLString NVARCHAR(MAX),
#Filename VARCHAR(500), -- Pass file name here
#ApplicantID VARCHAR(500) --Pass Application ID here
SET #SQLString = '
Insert Into Attachments
(
ApplicantID,
FileName,
FileBinary
)
SELECT #ApplicantID,#Filename,FileBinary
FROM OPENROWSET(BULK N''' + #ImagePath
+ ''',SINGLE_BLOB) AS FileBinary(FileBinary);'
EXEC Sp_executesql
#SQLString,
N'#Filename varchar(500),#ApplicantID varchar(500)',
#Filename =#Filename,
#ApplicantID=#ApplicantID

How to use local-name(.) within dynamic sql statement

I have the following code to create a SQL function that will parse an XML string and create a table of key value pairs that represent the nodes and values. This works fine for me in my use cases.
CREATE FUNCTION XmlToKeyValue
(
#rootName AS varchar(256),
#xml AS Xml
)
RETURNS #keyval TABLE ([key] varchar(max), [value] varchar(max))
AS
BEGIN
DECLARE #input TABLE (XmlData XML NOT NULL)
INSERT INTO #input VALUES(#xml)
INSERT #keyval ([key], [value])
SELECT
XC.value('local-name(.)', 'varchar(max)') AS [key],
XC.value('(.)[1]', 'varchar(max)') AS [value]
FROM
#input
CROSS APPLY
XmlData.nodes('/*[local-name()=sql:variable("#rootName")]/*') AS XT(XC)
RETURN
END
What I am trying to do is have a stored procedure in my main database that will create another database with all the appropriate functions/procedures/etc. So in that stored procedure I am trying to do something like this:
SET #cmd = '
CREATE FUNCTION XmlToKeyValue
(
#rootName AS varchar(256),
#xml AS Xml
)
RETURNS #keyval TABLE ([key] varchar(max), [value] varchar(max))
AS
BEGIN
DECLARE #input TABLE (XmlData XML NOT NULL)
INSERT INTO #input VALUES(#xml)
INSERT #keyval ([key], [value])
SELECT
XC.value(''local-name(.)'', ''varchar(max)'') AS [key],
XC.value(''(.)[1]'', ''varchar(max)'') AS [value]
FROM
#input
CROSS APPLY
XmlData.nodes(''/*[local-name()=sql:variable("#rootName")]/*'') AS XT(XC)
RETURN
END
'
BEGIN TRY
EXEC(N'USE '+#dbName+'; EXEC sp_executesql N''' + #cmd + '''; USE master')
END TRY
BEGIN CATCH
PRINT 'Error creating XmlToKeyValue'
Print Error_Message();
RETURN
END CATCH
However, I am getting the following error that I can't figure out how to resolve.
Error creating XmlToKeyValue
Incorrect syntax near 'local'.
Can I use local-name in a dynamic sql statement? If not, how can I achieve my goal? Thank you.
The problem is not the local-name function. It is entirely the fact that you are concatenating in the #cmd variable into your Dynamic SQL without properly escaping the embedded single-quotes.
This line:
EXEC(N'USE '+#dbName+'; EXEC sp_executesql N''' + #cmd + '''; USE master')
should be:
SET #cmd = REPLACE(#cmd, N'''', N'''''');
EXEC(N'USE ' + #dbName + N'; EXEC sp_executesql N''' + #cmd + N''';');
Else you are embedding:
XC.value(''local-name(
into the string, but using the same number of escape sequences, hence the XC.value( now becomes the end of the string and the local-name(.) is technically unescaped SQL and not part of a string.
Also:
You don't need the USE master at the end of the Dynamic SQL (so I removed it).
You prefixed the first string literal with N but none of the others (I added the N in for the others so that they all have that prefix).

How to use a variable in Openrowset to Loop over all XML files

I am trying to read an XML file using OpenRowSet from a folder and have been unable to do so and get the error
Cannot bulk Load since the "' #FullFilename'' does not exist.
Would appreciate if one could suggest how I can correct the problem
to obtain all data from each of the XML files.
Thanks.
Code:
declare #Directory varchar(50)
select #Directory = 'E:\XML\'
DECLARE #CD TABLE (XMLData XML);
declare #FileExist int
DECLARE #FileName varchar(500),
#DeleteCommand varchar(1000),
#FullFileName varchar(500)
DECLARE #SQL NVARCHAR(1000),#xml xml
--This is so that we know how long the loop lasts
declare #LoopID int, #MaxID int
SELECT #LoopID = min(id),#MaxID = max(ID)
FROM #tempList
WHILE #LoopID <= #MaxID
BEGIN
SELECT #FileNAme = filename
from #tempList
where id = #LoopID
SELECT #FullFileName = #Directory + #FileName
print #FULLFileName
exec xp_fileexist #FullFileName , #FileExist output
if #FileExist =1 --sanity check in case some evil person removed the file
begin
---********************************Problem with #FullFileName----------------
INSERT INTO #CD
SELECT *
FROM OPENROWSET(BULK ''' + #FullFileName +''' ,Single_BLOB) as rs
---********************************------------
select * from #CD
--SET #DeleteCommand = 'del ' + #Directory + #FileName
--maybe you want to delete or move the file to another directory
-- ** here is how to delete the files you just imported
-- uncomment line below to delete the file just inserted
--EXEC MASTER..XP_CMDSHELL #DeleteCommand
-- ** end of here is how to delete the files
end
--Get the next id, instead of +1 we grab the next value in case of skipped id values
SELECT #LoopID = min(id)
FROM #tempList
where id > #LoopID
END
select * from #tempList
This works and I am able to get the XML data from the specified file
DECLARE #CD TABLE (XMLData XML);
Declare #get_GeneralID bigint
INSERT INTO #CD
SELECT *
FROM OPENROWSET(BULK N'E:\XML\TestResult.XML', SINGLE_BLOB) rs;
select * from #CD
PS: I have put together from code that I found from the web.
I don't think you can use T-SQL variables in your OPENROWSET command - those things need to be fully and explicitly spelled out.
If you need to do this over a list of XML files, you'll have to create your T-SQL command as a string and then use dynamic SQL to execute that command.

Resources