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)
Related
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
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
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
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!
Can I call a remote webservice from a Stored Procedure and use the values that areretuned?
If you're using SQL 2005/2008, you could do this from a CLR stored procedure if you have the ability to install and run these. For more info:
http://msdn.microsoft.com/en-us/library/ms190790.aspx
Service Broker might provide the sort of functionality you're looking for here.
As The AntiSanta says, using a CLR stored procedure this is possible. The real question is whether you can avoid it altogether. It feels upside-down to call a web service from a stored procedure. Ideally you'd have some other service/app/layer that calls both the stored procedure and a web service. Possibly the stored proc returns parameter values for the web service, and you commit your local transaction after the WS call is complete.
This would make both debugging, deployment and support much more simple in the long run, and decouples the direct reference between the stored proc and the web service.
On SQL Server 2000 and up (if CLR is not enabled), you can use COM through stored procedures (sp_OACreate, sp_OAMethod, etc) if you have an existing COM wrapper for your web service.
Here is my code that works.
exec #hr = sp_OACreate 'MSXML2.ServerXMLHttp', #obj OUT
if #hr < 0 begin Raiserror('sp_OACreate MSXML2.ServerXMLHttp failed',16,1)
return end
exec #hr = sp_OAMethod #obj, 'Open', NULL, 'GET', #UrlString, false
if #hr <0 begin set #msg = 'sp_OAMethod Open failed' goto eh end
exec #hr = sp_OAMethod #obj, 'send'
if #hr <0 begin set #msg = 'sp_OAMethod Send failed' goto eh end
exec #hr = sp_OAGetProperty #obj, 'status', #status OUT
if #hr <0 begin set #msg = 'sp_OAMethod read status failed' goto eh end
if #status <> 200 begin set #msg = 'sp_OAMethod http status ' +str(#status) goto eh end
exec #hr = sp_OAGetProperty #obj, 'responseText', #response OUT
if #hr <0 begin set #msg = 'sp_OAMethod read response failed' goto eh end
exec #hr = sp_OADestroy #obj
select #response
......
eh:
exec #hr = sp_OADestroy #obj
Raiserror(#msg, 16, 1)
Return