Insert file to SQL Server without front end using stored procedure - sql-server

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

Related

Variable should be declared

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.

Use SQL OpenRowSet BulkColumn to Insert data from .txt File

I want to execute the OpenRowSet command to pull the contents of a .txt file into 1 column. In my script, I need to loop through a collection of existing records and build a dynamic file path for each .txt file I want to import into the database, and therefore, I am using the sp_executesql procedure to execute the OpenRowSet command and output the contents of the .txt file to an output parameter.
I have tested OpenRowSet with a hard-coded file path and without passing it to the sp_executesql procedure, and I am able to retrieve the .txt file contents and insert it into my desired table in SQL. All of that is working. The issue I run into with the sp_executesql procedure is the output parameter is coming back empty. Here is a snip of the code I am running in MSSQL SMS version 15.0.18206.0 on Windows Server 2019.
DECLARE #rootDirectory VARCHAR(100)
DECLARE #filePathWithName VARCHAR(255)
DECLARE #txtFileContents VARCHAR(MAX)
DECLARE #commandText NVARCHAR(MAX)
Set #commandText = N'(Select BulkColumn FROM OPENROWSET (BULK '''+ #rootDirectory + #filePathWithName + ''', SINGLE_CLOB) Myfile)'
-- Print the command text, should contain full text file path.
print 'Command Text: ' + #commandText
-- Execute command and output text file contents.
EXEC sp_executesql #commandText,
N'#fileContentsOut VARCHAR(MAX) OUTPUT',
#fileContentsOut = #txtFileContents OUTPUT;
-- Select the file contents output.
SELECT #txtFileContents; -- <-- comes back empty???
When I execute the command above, I get a query result window that shows the contents of the .txt file in a column called "BulkColumn", but #txtFileContents parameter is empty.
Here is what the #commandText looks like before executed:
Command Text: (Select BulkColumn FROM OPENROWSET (BULK 'F:\Assets\mypath\myfile12345.TXT', SINGLE_CLOB) Myfile)
I don't understand why #txtfileContents comes back empty when I select it.
Try this instead:
DECLARE #txtFileContents VARCHAR(MAX);
SELECT #txtFileContents = BulkColumn
FROM OPENROWSET ( BULK 'F:\Assets\mypath\myfile12345.TXT', SINGLE_CLOB ) AS x;
SELECT #txtFileContents AS TxtFileContents;
UPDATE:
I am iterating through a list of records and building a dynamic file path each time through...
This works for me:
DECLARE
#cmd nvarchar(1000),
#file nvarchar(255) = 'F:\Assets\mypath\myfile12345.TXT',
#txtFileContents varchar(MAX);
SET #cmd = FORMATMESSAGE ( 'SELECT #txtFileContents = BulkColumn FROM OPENROWSET ( BULK ''%s'', SINGLE_CLOB ) AS x;', #file );
EXEC sp_executesql #cmd, N'#txtFileContents varchar(MAX) OUT', #txtFileContents = #txtFileContents OUT;
SELECT #txtFileContents AS TxtFileContents;
It turns out you're missing SELECT #fileContentsOut = BulkColumn in your #commandText.
This:
SET #commandText = N'SELECT BulkColumn FROM OPENROWSET (BULK '''+ #rootDirectory + #filePathWithName + ''', SINGLE_CLOB) Myfile;'
Needs to be:
SET #commandText = N'SELECT #fileContentsOut = BulkColumn FROM OPENROWSET (BULK '''+ #rootDirectory + #filePathWithName + ''', SINGLE_CLOB) Myfile;'
Could use SSIS with a for each loop container.
https://www.red-gate.com/simple-talk/sql/ssis/ssis-basics-introducing-the-foreach-loop-container/

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
'

Column name not working when placed inside a variable in SQL Server [duplicate]

create procedure sp_First
#columnname varchar
AS
begin
select #columnname from Table_1
end
exec sp_First 'sname'
My requirement is to pass column names as input parameters.
I tried like that but it gave wrong output.
So Help me
You can do this in a couple of ways.
One, is to build up the query yourself and execute it.
SET #sql = 'SELECT ' + #columnName + ' FROM yourTable'
sp_executesql #sql
If you opt for that method, be very certain to santise your input. Even if you know your application will only give 'real' column names, what if some-one finds a crack in your security and is able to execute the SP directly? Then they can execute just about anything they like. With dynamic SQL, always, always, validate the parameters.
Alternatively, you can write a CASE statement...
SELECT
CASE #columnName
WHEN 'Col1' THEN Col1
WHEN 'Col2' THEN Col2
ELSE NULL
END as selectedColumn
FROM
yourTable
This is a bit more long winded, but a whole lot more secure.
No. That would just select the parameter value. You would need to use dynamic sql.
In your procedure you would have the following:
DECLARE #sql nvarchar(max) = 'SELECT ' + #columnname + ' FROM Table_1';
exec sp_executesql #sql, N''
Try using dynamic SQL:
create procedure sp_First #columnname varchar
AS
begin
declare #sql nvarchar(4000);
set #sql='select ['+#columnname+'] from Table_1';
exec sp_executesql #sql
end
go
exec sp_First 'sname'
go
This is not possible. Either use dynamic SQL (dangerous) or a gigantic case expression (slow).
Create PROCEDURE USP_S_NameAvilability
(#Value VARCHAR(50)=null,
#TableName VARCHAR(50)=null,
#ColumnName VARCHAR(50)=null)
AS
BEGIN
DECLARE #cmd AS NVARCHAR(max)
SET #Value = ''''+#Value+ ''''
SET #cmd = N'SELECT * FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + #Value
EXEC(#cmd)
END
As i have tried one the answer, it is getting executed successfully but while running its not giving correct output, the above works well
You can pass the column name but you cannot use it in a sql statemnt like
Select #Columnname From Table
One could build a dynamic sql string and execute it like EXEC (#SQL)
For more information see this answer on dynamic sql.
Dynamic SQL Pros and Cons
As mentioned by MatBailie
This is much more safe since it is not a dynamic query and ther are lesser chances of sql injection . I Added one situation where you even want the where clause to be dynamic . XX YY are Columns names
CREATE PROCEDURE [dbo].[DASH_getTP_under_TP]
(
#fromColumnName varchar(10) ,
#toColumnName varchar(10) ,
#ID varchar(10)
)
as
begin
-- this is the column required for where clause
declare #colname varchar(50)
set #colname=case #fromUserType
when 'XX' then 'XX'
when 'YY' then 'YY'
end
select SelectedColumnId from (
select
case #toColumnName
when 'XX' then tablename.XX
when 'YY' then tablename.YY
end as SelectedColumnId,
From tablename
where
(case #fromUserType
when 'XX' then XX
when 'YY' then YY
end)= ISNULL(#ID , #colname)
) as tbl1 group by SelectedColumnId
end
First Run;
CREATE PROCEDURE sp_First #columnname NVARCHAR(128)--128 = SQL Server Maximum Column Name Length
AS
BEGIN
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT ' + #columnname + ' FROM Table_1'
EXEC(#query)
END
Second Run;
EXEC sp_First 'COLUMN_Name'
Please Try with this.
I hope it will work for you.
Create Procedure Test
(
#Table VARCHAR(500),
#Column VARCHAR(100),
#Value VARCHAR(300)
)
AS
BEGIN
DECLARE #sql nvarchar(1000)
SET #sql = 'SELECT * FROM ' + #Table + ' WHERE ' + #Column + ' = ' + #Value
--SELECT #sql
exec (#sql)
END
-----execution----
/** Exec Test Products,IsDeposit,1 **/

MSSQL : Insert value of execute statement together with another string in a table

What I have
I am currently inserting all the SQL files from the current directory in a temporary table :
create table #tmpSQLFiles(SQLFileName varchar(max))
set #SqlStatement = 'master.dbo.xp_cmdshell ''dir /b "' + #DirPath + '*.sql"'''
insert into #tmpSQLFiles
execute (#SqlStatement)
This works well.
What I want
Now I want the table to have an extra varchar column in which I can store a certain desired string :
create table #tmpSQLFiles(SQLFileName varchar(max), MyString varchar(max))
set #SqlStatement = 'master.dbo.xp_cmdshell ''dir /b "' + #DirPath+ '*.sql"'''
What I have tried
How can I do the insert? I have tried :
insert into #tmpSQLFiles (SQLFileName, MyString) values (execute (#SqlStatement), 'aa')
or :
declare #ExecutedStmt varchar(max)
set #ExecutedStmt = execute (#SqlStatement)
-- But the above line is not correct.
Any of these 2 would work for me. I don't want to insert and update afterwards the second column.
Any ideas on how I can achieve this? Thank you !
Try using a table variable as an intermediary - not the prettiest, but does the job:
create table #tmpSQLFiles(SQLFileName varchar(max), MyString varchar(max))
set #SqlStatement = 'master.dbo.xp_cmdshell ''dir /b "' + #DirPath + '*.pdf"'''
DECLARE #TempOutpt TABLE ([output] varchar(500))
insert into #TempOutpt ([output])
execute (#SqlStatement)
insert into #tmpSQLFiles (SQLFileName, MyString)
select [output], 'my string here' from #TempOutpt
select * from #tmpSQLFiles
If you weren't using an extended stored procedure (xp_cmdshell), you might have been able to use OPENROWSET to execute the SP:
SELECT *fields*
FROM OPENROWSET('SQLNCLI',
'Server=*your_server*;Trusted_Connection=yes;Database=*your_database*',
'exec *stored_procedure* *parameters*')
You need to use an output parameter so you can use the results in the next INSERT:
DECLARE #result INT, #sql NVARCHAR(512)
SET #sql = N'SELECT #result = COUNT(*) FROM ' + #dbname + '.INFORMATION_SCHEMA.TABLES'
EXEC sp_executesql
#query = #sql,
#params = N'#result INT OUTPUT',
#result = #result OUTPUT
PRINT #result

Resources