Using Column value as foldername when exporting images MSSQL - sql

When exporting images using MSSQL, is there a way to specify a columns value as a new folder name?
For example, I have a field called ReportID that I would like a folder to be created inside my already created "images" folder if it doesn't already exist, (multiple records could hold the same ReportID).
My script is as follows: (the correct file path is being written, but no images are being saved, and I assume it's not creating folders properly)
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
DECLARE #file int,
#FilePath varchar(80),
#hr INT,
#FK_ReferenceID INT,
#FK_FieldID INT,
#Value VARBINARY(MAX),
#Extension varchar(4),
#ReportID INT;
DECLARE imgs CURSOR
FOR SELECT FK_ReferenceID, FK_FieldID, Value, Extension, ReportID FROM dbo.ImageValues
FOR UPDATE OF FilePath;
OPEN imgs;
FETCH NEXT FROM imgs INTO #FK_ReferenceID, #FK_FieldID, #Value, #Extension, #ReportID;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #FilePath = 'E:\Reports\images\' + CAST(#ReportID AS VARCHAR(10)) + '\' + CAST(#FK_ReferenceID AS VARCHAR(10)) + '-f' + CAST(#FK_FieldID AS VARCHAR(10)) + '.' + CAST(#Extension AS VARCHAR(4));
EXEC sp_OACreate 'ADODB.Stream', #file OUT;
EXEC sp_OASetProperty #file, 'Type', 1;
EXEC sp_OAMethod #file, 'Open';
EXEC sp_OAMethod #file, 'Write', NULL, #Value;
EXEC sp_OAMethod #file, 'SaveToFile', NULL, #FilePath, 2;
EXEC sp_OAMethod #file, 'Close';
EXEC sp_OADestroy #file;
UPDATE dbo.ImageValues SET FilePath = #FilePath WHERE CURRENT OF imgs;
FETCH NEXT FROM imgs INTO #FK_ReferenceID, #FK_FieldID, #Value, #Extension, #ReportID;
END
CLOSE imgs;
DEALLOCATE imgs;
GO
sp_configure 'Ole Automation Procedures', 0;
GO
RECONFIGURE;
GO

One way to do this is to break this into 2 steps, (1) create the folders first anyways and (2) then the file. You would need to check for exceptions in both steps, in the first step you would ignore if the exception that folder already exists. Alternatively you could first check if the folder exists and then create it and then the file. As far as I know, SQL automatically would not do such checks for you.

Related

OLE Procedures, query executed succesfully; No File Extracted

I am trying to extract a blob file from SQL Server. I was able to get it to execute successfully but when I look in my Desktop\consol\output directory, the file isn't there (refreshed, still nothing). Here is the code:
SELECT * FROM FileWarehouse
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
DECLARE #SQLIMG VARCHAR(MAX),
#File VARBINARY(MAX),
#OpPath VARCHAR(MAX),
#ObjectToken INT
SELECT #File = StoredFile FROM [dbo].[FileWarehouse] WHERE Id= 157994
SET #OpPath = 'C:\Users\Nick\Desktop\consol\output\marksheet.doc'
EXEC sp_OACreate 'ADODB.Stream', #ObjectToken OUTPUT
EXEC sp_OASetProperty #ObjectToken, 'Type', 1
EXEC sp_OAMethod #ObjectToken, 'Open'
EXEC sp_OAMethod #ObjectToken, 'Write', NULL, #File
EXEC sp_OAMethod #ObjectToken, 'SaveToFile', NULL, #OpPath, 2
EXEC sp_OAMethod #ObjectToken, 'Close'
EXEC sp_OADestroy #ObjectToken
GO
In the SELECT statement, dbo.[FileWarehouse] and StoredFile are both underlined, saying 'Invalid Object Name' and 'Invalid Column Name', respectively. They are definitely valid, so I'm not sure it's saying that. Here is the tutorial I was following https://www.youtube.com/watch?v=8g7_F3Ice6E .
Any help would be greatly appreciated. Thank You.
While Dan's answer is correct (use Powershell or SQL CLR instead), the reason your COM automation isn't working, is that you've failed to capture and inspect the return codes from the extended stored procedures.
Here's an example:
--exec sp_configure 'Show Advanced Options', 1
--reconfigure
--exec sp_configure 'Ole Automation Procedures', 1
--reconfigure
declare #url varchar(2000) = 'http://www.bing.com'
declare #hr int;
declare #win int;
begin try
EXEC #hr=sp_OACreate 'WinHttp.WinHttpRequest.5.1',#win OUT
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win, 'Open',NULL,'GET',#url,'false'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win,'Send'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
declare #status int
EXEC #hr=sp_OAGetProperty #win,'Status', #status out
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
if #status <> 200
begin;
declare #msg varchar(2000) = concat('web request failed ', #status);
throw 60000, #msg, 1;
end;
declare #response table(text nvarchar(max));
insert into #response(text)
EXEC #hr=sp_OAGetProperty #win,'ResponseText';
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
select * from #response;
EXEC #hr=sp_OADestroy #win
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
end try
begin catch
EXEC #hr=sp_OADestroy #win
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
throw;
end catch
The IntelliSense error is erroneous if the script runs.
I suggest you generally avoid the ole automation procs for new development. If you don't really need to use T-SQL to create the file, consider a simple PowerShell script. This is more robust and flexible for ad-hoc needs. Below is an example that uses the standard ADO.NET objects.
$connection = New-Object System.Data.SqlClient.SQLConnection("Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI")
$command = New-Object System.Data.SqlClient.SqlCommand("SELECT StoredFile FROM [dbo].[FileWarehouse] WHERE Id= 157994;", $connection)
$connection.Open()
$blob = $connection.ExecuteScalar()
$connection.Close()
[System.IO.File]::WriteAllBytes("C:\Users\Nick\Desktop\consol\output\marksheet.doc", $blob)

Binary images to file

I have a table called ImageValues. In it, I have columns labeled RecordID, ReportID and Image. The image is stored as an IMAGE data type. I want to extract the image to a file and write the file path into another column labeled FilePath. Preferably, the filename would be "RecordID-ReportID"
I am using SQL Server
Can this be done?
One of the ways to do it is using OLE automation, which you can enable if you have administrator privileges on the machine. Here's some sample code, liberally borrowed from this SO answer:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
DECLARE #file int,
#FilePath varchar(80),
#hr INT,
#RecordID INT,
#ReportID INT,
#Image VARBINARY(MAX);
DECLARE imgs CURSOR
FOR SELECT RecordID, ReportID, "Image" FROM dbo.ImageValues
FOR UPDATE OF FilePath;
OPEN imgs;
FETCH NEXT FROM imgs INTO #RecordID, #ReportID, #Image;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #FilePath = 'E:/' + CAST(#RecordID AS VARCHAR(10)) + '-' + CAST(#ReportID AS VARCHAR(10)) + '.jpg';
EXEC sp_OACreate 'ADODB.Stream', #file OUT;
EXEC sp_OASetProperty #file, 'Type', 1;
EXEC sp_OAMethod #file, 'Open';
EXEC sp_OAMethod #file, 'Write', NULL, #Image;
EXEC sp_OAMethod #file, 'SaveToFile', NULL, #FilePath, 2;
EXEC sp_OAMethod #file, 'Close';
EXEC sp_OADestroy #file;
UPDATE dbo.ImageValues SET FilePath = #FilePath WHERE CURRENT OF imgs;
FETCH NEXT FROM imgs INTO #RecordID, #ReportID, #Image;
END
CLOSE imgs;
DEALLOCATE imgs;
GO
sp_configure 'Ole Automation Procedures', 0;
GO
RECONFIGURE;
GO
Note that all files are going to be stored with the extension '.jpg', but you could extend it to detect the image type based on the magic number.
If you're using SQL Server 2012 or later, you could also use a cool feature called FileTables. Read up on them here, and also here for ways of inserting data into a FileTable using T-SQL. After that, you can simply copy the files wherever you want using Windows Explorer.

Verify data integrity for varbinary column

I am inserting a .jpg into a varbinary(max) column in SQL Server 2012 using the following command:
INSERT INTO Employees
VALUES(5, (SELECT * FROM OPENROWSET(BULK N'C:\4.jpg',SINGLE_BLOB) AS image))
It inserts a record in the table.
Then I used the following command to restore the file from db to file system.
BCP "SELECT pic FROM Employees where id=5" queryout "C:\51.jpg" -N -T
When I try to view the downloaded file using image viewer, I get an error
File is damaged.
Any ideas?
This worked for me: How to export image field to file?
The short version without the cursor looks like this:
DECLARE #ImageData VARBINARY(max)
DECLARE #FullPathToOutputFile NVARCHAR(2048);
SELECT #ImageData = pic FROM Employees WHERE id=5
SET #FullPathToOutputFile = 'C:\51.jpg'
DECLARE #ObjectToken INT
EXEC sp_OACreate 'ADODB.Stream', #ObjectToken OUTPUT;
EXEC sp_OASetProperty #ObjectToken, 'Type', 1;
EXEC sp_OAMethod #ObjectToken, 'Open';
EXEC sp_OAMethod #ObjectToken, 'Write', NULL, #ImageData;
EXEC sp_OAMethod #ObjectToken, 'SaveToFile', NULL, #FullPathToOutputFile, 2;
EXEC sp_OAMethod #ObjectToken, 'Close';
EXEC sp_OADestroy #ObjectToken;
Before you can do that you have execute this only once in your database:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
All credits belong to #mathijsuitmegen :) thanks for this working solution

How to save many pdf files into a folder in sql server

I have many pdf files in my database and I want to store them in a folder based on priority. When I use the code below I am unable to save all files; it just saves one file. :(
Declare
#File_Path_1 VARBINARY(MAX),
#FileName_1 VARCHAR(MAX),
#Timestamp_1 varchar(max),
#objectToken_1 int
DECLARE cFiles CURSOR FAST_FORWARD FOR
SELECT request_number from data where priority=1
OPEN cFiles
FETCH NEXT FROM cFiles INTO #FileName_1
WHILE ##FETCH_STATUS = 0 BEGIN
SET #FileName_1 = #FileName_1
set #Timestamp_1='c:\Dump\1.pdf'
EXEC sp_oacreate 'ADODB.Stream', #ObjectToken_1 OUTPUT
EXEC sp_oasetproperty #objecttoken_1, 'type', 1
EXEC sp_oamethod #objecttoken_1,'open'
EXEC sp_oamethod #objecttoken_1,'Write',Null,#File_Path_1
EXEC sp_oamethod #objecttoken_1,'Savetofile',Null,#Timestamp_1,2
EXEC sp_oamethod #objecttoken_1,'Close'
EXEC sp_oamethod #objecttoken_1,'open'
FETCH NEXT FROM cFiles INTO #FileName_1
END
CLOSE cFiles
DEALLOCATE cFiles
the code above fetches me just one record can any one please help in
DECLARE #SOURCEPATH VARBINARY(MAX),
#DESTPATH VARCHAR(MAX),
#ObjectToken INT,
#Request_Number varchar(30)
DECLARE PDFPATH CURSOR FAST_FORWARD FOR
SELECT ID from Table
OPEN PDFPATH
FETCH NEXT FROM PDFPATH INTO #SOURCEPATH, #Request_Number
WHILE ##FETCH_STATUS = 0
BEGIN
SET #DESTPATH = 'C:\path' + CAST(#Request_Number AS varchar) + '.pdf'
EXEC sp_OACreate 'ADODB.Stream', #ObjectToken OUTPUT
EXEC sp_OASetProperty #ObjectToken, 'Type', 1
EXEC sp_OAMethod #ObjectToken, 'Open'
EXEC sp_OAMethod #ObjectToken, 'Write', NULL, #SOURCEPATH
EXEC sp_OAMethod #ObjectToken, 'SaveToFile', NULL, #DESTPATH, 2
EXEC sp_OAMethod #ObjectToken, 'Close'
EXEC sp_OADestroy #ObjectToken
FETCH NEXT FROM PDFPATH INTO #SOURCEPATH, #Request_Number
END
I Hope this snippet helps people who are in need :) Thank you all for helping me :)
The main problem is that you are not dynamically creating the filename:
set #Timestamp_1='c:\Dump\1.pdf'
should be something like:
set #Timestamp_1='c:\Dump\' + CONVERT(VARCHAR(50), #FileName_1) + '.pdf'
And you don't seem to be getting the source data to write out; #File_Path_1 is never set. You need to add a field to the SELECT list and add the #File_Path_1 variable to the FETCH statement.
Also, this line doesn't do anything:
SET #FileName_1 = #FileName_1

How to call webservice from TSQL? (SQL SERVER 2000)

I want to call a webservice from TSQL in SQL Server 2000. I tried with the following code:
Declare #Object as Int;
Declare #ResponseText as Varchar(8000);
Exec sp_OACreate 'MSXML2.XMLHTTP', #Object OUT;
Exec sp_OAMethod #Object, 'open', NULL, 'get','http://server/ws/service1.asmx/Test', 'false';
Exec sp_OAMethod #Object, 'send';
Exec sp_OAMethod #Object, 'responseText', #ResponseText OUTPUT;
Select #ResponseText Resultado;
Exec sp_OADestroy #Object;
For this to work I had to enable Ole Automation:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
In my test server works fine, the problem is that on the production server to run
sp_configure 'Ole Automation Procedures', 1;
I get the following error:
The configuration option 'Ole Automation Procedures' does not exist, or it may be an advanced option.
When running
exec sp_configure
on the test server brings the record "Ole Automation Procedures" on the production server not.
Update
I modify the code to catch the error:
Declare #Object as Int;
Declare #ResponseText as Varchar(8000);
Exec sp_OACreate 'MSXML2.XMLHTTP', #Object OUT;
Exec sp_OAMethod #Object, 'open', NULL, 'get','http://server/ws/service1.asmx/Test', 'false';
Exec sp_OAMethod #Object, 'send';
Exec sp_OAMethod #Object, 'responseText', #ResponseText OUTPUT;
EXEC sp_OAGetErrorInfo #Object
Select #ResponseText Resultado;
Exec sp_OADestroy #Object;
The instruction "sp_OAGetErrorInfo EXEC # Object" return: (0x8004271A
) Error in srv_convert.
According to Microsoft (link) is a problem of SqlServer. Since in my case the result of the webservice exceed 4000 characters.
How I can call a webservice from TSQL?
I just stumbled upon same error - "(0x8004271A ) Error in srv_convert."
To overcome char limitations, use #tmp table like below:
Create table #tmp(dt nvarchar(max))
insert into #tmp
exec #hr =sp_OAGetProperty #objWinHttp, 'ResponseText'
Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
Solution Source
heey i have maybe some help for you if you want to call to call a HTTP web service from T-SQL (no SQLCLR) You can automate the XMLHTTP server object using the Object Automation extended stored procedures.
Example
I suggest you use the CLR or an SSIS package though.
I solved it the following way:
Create a VBScript file (callWS.vbs) with the following code:
if WScript.Arguments.Count = 1 then
Set http = CreateObject("Microsoft.XmlHttp")
http.open "GET", WScript.Arguments(0), FALSE
http.send ""
WScript.Echo http.responseText
else
WScript.Echo "Not was provided the WS address."
end if
Then in TSQL:
declare #Command varchar(100)
declare #RetInfo varchar(8000)
select #Command = 'cscript c:\callWS.vbs "http://server/ws/service1.asmx/Test"'
print #Command
exec #RetInfo = master.dbo.xp_cmdshell #Command
print #RetInfo