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

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

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)

Writing nvarchar to a text file

I have a problem with writing in a text file. Everything works fine when my text is ASCII:
DECLARE #OLE INT
DECLARE #FileId INT
DECLARE #File VARCHAR(max) = 'D:\test.txt'
DECLARE #Text NVARCHAR(max) = N'no problem when writing in english!'
EXECUTE sp_OACreate 'Scripting.FileSystemObject',#OLE OUT
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileId OUT, #File,2,1
EXECUTE sp_OAMethod #FileId, 'WriteLine', Null, #Text
But nothing will be appeared in the file when my text has Unicode characters:
DECLARE #Text NVARCHAR(max) = N'من نمایش داده نمیشم'
I also tried sp_OASetProperty but that did not work (mentioned here):
EXECUTE sp_OASetProperty #OLE, 'Charset', 'UTF-8'
Any idea to fix this or using other T-SQL procedures?
According to the Scripting.FileSystemObject documentation, the CreateTextFile method takes a Boolean value to create a Unicode file. You could change the T-SQL code to use that method instead of OpenTextFile.
EDIT:
Below is an example using OpenTextFile per Tom's comment. I change the iomode value in your original code from 1 to 8 to match the documentation and added the close and destroy in case your full code is missing those important tasks.
DECLARE #OLE INT;
DECLARE #FileId INT;
DECLARE #File VARCHAR(max) = 'c:\test.txt';
DECLARE #Text NVARCHAR(max) = N'من نمایش داده نمیشم';
EXECUTE sp_OACreate 'Scripting.FileSystemObject',#OLE OUT;
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileId OUT, #File,8,1,-1;
EXECUTE sp_OAMethod #FileId, 'WriteLine', Null, #Text;
EXECUTE sp_OAMethod #FileId, 'Close';
EXECUTE sp_OADestroy #FileId OUT;
EXECUTE sp_OADestroy #OLE OUT;
EXECUTE #HR = sp_OACreate 'ADODB.Stream', #OLE OUTPUT
EXECUTE sp_OASetProperty #OLE, 'Type', 2
EXECUTE sp_OASetProperty #OLE, 'Mode', 3
EXECUTE sp_OASetProperty #OLE, 'Charset', 'Windows-1256'
EXECUTE sp_OASetProperty #OLE, 'LineSeparator', 'adLF'
EXECUTE sp_OAMethod #OLE, 'Open'
EXECUTE sp_OAMethod #OLE, 'WriteText', NULL, #String
--Commit data and close text stream
EXECUTE sp_OAMethod #OLE,'SaveToFile', NULL, #FileAndPath, 2
EXECUTE sp_OAMethod #OLE, 'Close'
EXECUTE sp_OADestroy #OLE

SQL - Create XML - How to set Unicode UTF-8

I have a problem with creating an XML file from inside a SQL PROCEDURE.
The XMLs get created and placed in the correct folder. Although when I open the file in XMLSpy, it says the following error:
Your file contains 3 character(s) that should not be present in a file using the Unicode UTF-8 encoding...
The offending characters are è (0xE8), ü (0xFC), é (0xE9)
When I open the XML file in Notepad++ and check for encoding (via menu Encoding on top), it says it is in ANSI and not in UTF-8.
So my question is: How do I get it to turn into UTF-8? Any suggestions?
The code of my procedure can be found below:
#File VARCHAR(2000) // parameter
AS
BEGIN
DECLARE #OLE INT
DECLARE #FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', #OLE OUT
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 1
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
EXECUTE sp_OAMethod #FileID, 'WriteLine', Null, #Text
EXECUTE sp_OADestroy #FileID
EXECUTE sp_OADestroy #OLE
END
EDIT 1
Changed my code, exporting to ASCII instead of Unicode (as suggested below by Wolf), but this didn't help too. But here is that part of code:
DECLARE #OLE INT
DECLARE #FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', #OLE OUT
EXECUTE sp_OAMethod #OLE, 'CreateTextFile', #FileID OUT, #File, 2, False
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
EXECUTE sp_OAMethod #FileID , 'Write', Null, #Text
EXECUTE sp_OAMethod #FileID , 'Close'
EXECUTE sp_OADestroy #FileID
EXECUTE sp_OADestroy #OLE
END
I found a solution via another way. (don't remember which website I found it)
See code below. This code will export my file in UTF-8-BOM encoding.
#File VARCHAR(2000)
AS
BEGIN
DECLARE #OLE INT
EXECUTE sp_OACreate 'ADODB.Stream', #OLE OUTPUT
DECLARE #Text XML
SET #Text = (SELECT TOP(1) [xml] from VW_WARP_LEVERANCIERS_XML)
DECLARE #Converted NVARCHAR(MAX)
SET #Converted = CONVERT(nvarchar(MAX), #Text)
EXECUTE sp_OASetProperty #OLE, 'Type', 2 --1 = binary, 2 = text
EXECUTE sp_OASetProperty #OLE, 'Mode', 3 --0 = not set, 1 read, 2 write, 3 read/write
EXECUTE sp_OASetProperty #OLE, 'Charset', 'UTF-8' --'ISO-8859-1'
EXECUTE sp_OASetProperty #OLE, 'LineSeparator', 'adLF'
EXECUTE sp_OAMethod #OLE, 'Open'
EXECUTE sp_OAMethod #OLE, 'WriteText', NULL, #Converted --text method
--Commit data and close text stream
EXECUTE sp_OAMethod #OLE, 'SaveToFile', NULL, #File, 2 --1 = notexist 2 = overwrite
EXECUTE sp_OAMethod #OLE, 'Close'
EXECUTE sp_OADestroy #OLE
EXECUTE sp_OADestroy #OLE
END
Generally, SQL Server does not support UTF-8 by itself. However, I'm not sure about FSO, maybe it does.
The OpenTextFile documentation states that you can determine the file format, i.e. ASCII or Unicode. Try:
EXECUTE sp_OAMethod #OLE, 'OpenTextFile', #FileID OUT, #File, 8, 0;
This should give you an ASCII file format.

Using Column value as foldername when exporting images MSSQL

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.

How to email query output

I have a basic query, and i'd like to email the results. How can I do this at the query level? So if my query is:
SELECT
Store_Id, Paid_Out_Amount, Paid_Out_Comment,
Paid_Out_Datetime, Update_UserName
FROM Paid_Out_Tb
WHERE (Store_Id = 1929) OR
(Paid_Out_Amount > 50) AND
(Paid_Out_Datetime BETWEEN
CONVERT(DATETIME, '2012-06-01 00:00:00', 102) AND
CONVERT(DATETIME, '2012-06-30 00:00:00', 102))
How would I email the output? I have a procedure to send email via SMTP and the parameters are #From, #To, #Subject and #body... which works.. How would I make the body the outcome of the query?
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
CREATE PROCEDURE [dbo].[sp_SQLNotify]
#From varchar(100) ,
#To varchar(100) ,
#Subject varchar(100)=" ",
#Body varchar(4000) = "Test"
/*********************************************************************
This stored procedure takes the above parameters and sends an e-mail.
All of the mail configurations are hard-coded in the stored procedure.
Comments are added to the stored procedure where necessary.
Reference to the CDOSYS objects are at the following MSDN Web site:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_messaging.asp
***********************************************************************/
AS
Declare #iMsg int
Declare #hr int
Declare #source varchar(255)
Declare #description varchar(500)
Declare #output varchar(1000)
--************* Create the CDO.Message Object ************************
EXEC #hr = sp_OACreate 'CDO.Message', #iMsg OUT
--***************Configuring the Message Object ******************
-- This is to configure a remote SMTP server.
-- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_schema_configuration_sendusing.asp
EXEC #hr = sp_OASetProperty #iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing").Value','2'
-- This is to configure the Server Name or IP address.
-- Replace MailServerName by the name or IP of your SMTP Server.
EXEC #hr = sp_OASetProperty #iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value', '10.1.1.10'
-- Save the configurations to the message object.
EXEC #hr = sp_OAMethod #iMsg, 'Configuration.Fields.Update', null
-- Set the e-mail parameters.
EXEC #hr = sp_OASetProperty #iMsg, 'To', #To
EXEC #hr = sp_OASetProperty #iMsg, 'From', #From
EXEC #hr = sp_OASetProperty #iMsg, 'Subject', #Subject
-- If you are using HTML e-mail, use 'HTMLBody' instead of 'TextBody'.
EXEC #hr = sp_OASetProperty #iMsg, 'TextBody', #Body
EXEC #hr = sp_OAMethod #iMsg, 'Send', NULL
-- Sample error handling.
IF #hr <>0
select #hr
BEGIN
EXEC #hr = sp_OAGetErrorInfo NULL, #source OUT, #description OUT
IF #hr = 0
BEGIN
SELECT #output = ' Source: ' + #source
PRINT #output
SELECT #output = ' Description: ' + #description
PRINT #output
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
RETURN
END
END
-- Clean up the objects created.
EXEC #hr = sp_OADestroy #iMsg
PRINT 'Mail Sent!'
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
This is the procedure i'm using to send the mail... which works... I just want to add a spot in it to send the results of the query above it... Can this be done easily within in the procedure?
Use the SQL Server Powershell pack. An example (with detailed explanation) of using it to obtain output is here.
(The above is taken from this SO answer, but to clarify something s/he says: SQL Server 2008 client components is required (Express should be fine), but it can work with SQL Server 2000 databases (source).)
You can also use a variable for a direct loop concatenation. See https://stackoverflow.com/a/4447564/1180926 (although you would use tab and newline delimiters instead of HTML code).
You would then just change your query accordingly, store it in #Body, and you're done!