tsql : can't select into <table> from proc - sql-server

I'm running sql server 2008 and I'm trying to run the query
OPEN CUR_InvHeader
FETCH NEXT FROM CUR_InvHeader INTO
#CH_iBilling_Log_RecID
WHILE (##FETCH_STATUS = 0) BEGIN --Loop for Cur_InvHeader
select * into tarInvoiceDetail_201101 FROM OPENROWSET('SQLNCLI', 'Server=(local);Trusted_Connection=yes;',
'EXEC _sp_cwm5_GetInvoiceDetail #CH_iBilling_Log_RecID')
I get the error
OLE DB provider "SQLNCLI10" for linked
server "(null)" returned message
"Deferred prepare could not be
completed.".
I've run sp_configure 'ad hoc..', 1
reconfigure with override
to ensure i can run the select against the openrecordset
any ideas what i might be doing wrong?
thanks in advance

The first thing that's wrong is that your "EXEC _sp_cwm5_GetInvoiceDetail #CH_iBilling_Log_RecID" statement will be evaluated as a constant, rather than pass the value of #CH_iBilling_Log_RecID through to OPENROWSET. You'd have to replace the whole "SELECT * INTO..." into a string variable and run sp_executesql on it.
The second thing wrong is that your "select into" statement will create tarInvoiceDetail_201101 every time, as INTO creates a new table when run. So if your cursor covers more than one row you'll get an error on the second pass.
Also, what does "Server=(local)" represent here? Are you trying to use OPENROWSET against your local copy of SQL Server while connected to a remote server? Or are you trying to use OPENROWSET to get around the limitation that you can't directly use a stored procedure as the source for an INSERT?

Related

Calling sp_cursoropen with Linked Server Throws Error

We recently moved a database to it's own SQL Server which broke a call to a stored proc wrapped in a sp_cursoropen statement.
The original call, which worked, was to a database on the same server as the calling database:
using database1
exec sp_cursoropen #p1 output, N'exec database2.dbo.sp_mystoredproc 1234'
We had to move the second database to its own server for compliance reasons and created a linked server between the two. We changed the call to:
using database1
exec sp_cursoropen #p1 output, N'exec LinkedDBServer.database2.dbo.sp_mystoredproc 1234'
The call no longer works and gives us two errors
A server cursor cannot be opened on the given statement or statements. Use a default result set or client cursor.
The cursor was not declared
The funny thing is that running the stored proc command on it's own works and returns rows of data:
using database1
exec LinkedDBServer1.database2.dbo.sp_mystoredproc 1234
Also funny, putting direct SQL from the stored proc itself and pasting it in place of sp_mystoredproc also works, even with the cursor:
using database1
exec sp_cursoropen #p1 output, N'Select * from LinkedDBServer1.Dbname.dbo.sometable where sometable.id = 1234'
This leads me to believe that the return type of the stored procedure that runs via a linked server is somehow different than that of the same stored procedure running on the same SQL server as the calling database. Unfortunately, I cannot find any documentation to support my hypothesis.
Does anyone know why a stored procedure that returns rows of data wouldn't play well with sp_cursoropen when a linked server is involved?
Note: I'm not interested in workarounds. I know there are many ways to fix this such as writing to a temp table first, using a different service to grab the data or some other method of completing the task. I'm only interested in what low level difference in the SQL server is causing this error even though the separate pieces being called to through the linked server work independently.

How to use OPENQUERY to properly execute a Stored Procedure that updates a linked server table?

I'm having a hard time trying to figure this out. I'm using OPENQUERY to execute Stored Procedures on a linked server.
I managed to find a way to do it, by using the following:
SELECT *
FROM OPENQUERY(
[LINKEDSRV\SQLSRV],
'SET FMTONLY OFF; SET NOCOUNT ON; EXEC [Database_Name_Example].Data.usp_GetNames 5,''S''')
GO
The reason I use SET FMTONLY OFF and SET NOCOUNT ON is because when I tried the code above without them, this message appeared:
Msg 7357, Level 16, State 1, Line 1
Cannot process the object "EXEC [Database_Name_Example].Data.usp_GetNames 5,'S'". The OLE DB provider "SQLNCLI" for linked server "LINKEDSRV\SQLSRV" indicates that either the object has no columns or the current user does not have permissions on that object.
Reading a lot online helped me find the answer. This blog for example: http://www.sommarskog.se/share_data.html#OPENQUERY
So far so good, until I stomped into a Stored Procedure that use SELECT and UPDATE some tables on the linked server. When I execute the OPENQUERY I get the results from the SELECT statement but I noticed that it does not update the table.
The Stored Procedure goes like this:
CREATE PROCEDURE Data.usp_GetNames (#year tinyint=NULL, #online char(1)=NULL)
if #online = 'S'
BEGIN
select nam_codig, nam_desc from Names
where nam_status = 'P'
order by nam_date
UPDATE Names
SET nam_status = 'S'
where nam_status = 'P'
END
When I execute it directly in the linked server it updates the table, so the second time I execute it, there will be no more nam_status = 'P'
But if I execute it with OPENQUERY the results are the same, it doesn't UPDATE it just select the data.
What can I do to allow the permissions?
Thank you!!!

Execute Stored Procedure with multiple result sets

I am using SSIS 2016. I need to execute a stored procedure that returns 4 result sets. I only need to keep the first result set and write this to a table. I can not modify the stored procedure. I do not care about any of the data returned in the other result sets. The stored procedure is in a SQL Server 2016 database. Results will also reside in SQL Server 2016.
I currently have this process running in SSIS 2008 using the "SQL Command" data access mode in an OLE DB Source like below. I have this in a For Each Loop Container to pass a series of param values to the stored procedure as I execute it multiple times for different param values on a daily basis.
SET FMTONLY OFF;
EXEC myProc
#Param1 = ?,
#Param2 =?,
#Param3 = ?;
By default SSIS 2008 is only returning the first result set, which has worked for me as I only care about the first result set.
I am using the Native OLEDB SQL Server client. From what I have read, it has changed the way it handles multiple result sets. I have used the WITH RESULT SETS to define the first result set but if I execute SSIS will fail indicating other result sets need to be defined.
In short, what is the best approach to duplicate what works in SSIS 2008 in SSIS 2016?
Solution Overview
I made 2 Experiments on that issue, the first experiments showed that in case of stored procedures with no parameters, nothing changed in SQL Server 2016 and SSIS 2016, the first Result Set is returned and others are ignored.
The second experiment showed that when using parameters, this will throw an exception, so you have to define metadata using WITH RESULT SETS option, then remove this option.
Detailed Solution
Experiment 1
The following experiment are made using SQL Server 2016 and Visual Studio 2015 with SSDT 2016
First i created this stored procedure
CREATE PROCEDURE sp_Test
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 10 PersonType,NameStyle,Title
FROM [AdventureWorks2016CTP3].[Person].[Person]
SELECT TOP 10 PersonType,Firstname,Lastname
FROM [AdventureWorks2016CTP3].[Person].[Person_json]
END
GO
Then i added a Data flow task to SSIS package
Added an OLEDB Source, Recordset destination
In OLEDB source i select the Data access mode to SQL command
an use the following commnad
EXEC sp_Test
When clicking on Columns Tab it shows the first ResultSet structure
And we i executed the package it runs succesfully
Experiment 2
I changed the stored procedures to the following:
ALTER PROCEDURE [dbo].[sp_Test]
#param1 varchar(10),
#param2 varchar(10),
#param3 varchar(10)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 10 PersonType,NameStyle,Title ,#param2 as 'Param'
FROM [AdventureWorks2016CTP3].[Person].[Person]
SELECT TOP 10 PersonType,Firstname,Lastname,#param3 as 'Param'
FROM [AdventureWorks2016CTP3].[Person].[Person_json]
END
And i used the following SQL Command in the OLEDB Source:
EXEC sp_Test ?,?,?
WITH RESULT SETS (
(
PersonType NVarchar(10),
NameStyle NVarchar(10),
Title NVarchar(10),
Param Varchar(10)
)
)
And i mapped the parameters correctly.
When running the package it throws the following exception.
[OLE DB Source 2] Error: SSIS Error Code DTS_E_OLEDBERROR. An OLE DB error has occurred. Error code: 0x80040E14.
An OLE DB record is available. Source: "Microsoft SQL Server Native Client 11.0" Hresult: 0x80040E14 Description: "EXECUTE statement failed because its WITH RESULT SETS clause specified 1 result set(s), and the statement tried to send more result sets than this.".
After that i tried to remove the With RESULT SETS option, so the command is :
EXEC sp_Test ?,?,?
I tried to execute the package again, so it is executed with no errors.
Conclusion
Try to use the WITH RESULT SETs option to define the OLEDB Source metadata, after that the metadata is defined, just remove this option and run the package, so it will just take the first Result Set succesfully.
I know it's not exactly what you are asking for, but maybe you could create another stored proc that will return only the first result set for you? (Without touching the first stored proc.) Or insert the data into a table for you and then you just read the data?

How to get a Recordset in SQL Server

I've seen in Oracle SQL that there is something called SYS_REFCURSOR which is used in a SP to get a recordset from a table
I want to do the same thing in SQL Server so I can a SP to get a recordset of a specific table. I've searched a lot looking for similar solutions but all what I've seen are all related to Oracle SQL.
Any suggestions please?
P.S. To be more clear, what do I want is just using an SP to select all records instead of the normal query.
i.e. instead of using:
SELECT * FROM EMP_DEPARTMENT
use SP to do the same thing.
Assuming you mean stored procedure with SP you can to this :
create procedure dbo.spMyProcedure as
begin
set nocount on
select * from emp_department
end;
than you can do this :
exec dbo.spMyProcedure
Is this what you mean ?
In SQL Server, you can simply encapsulated the SELECT query in a stored procedure (using * only as an example since an explicit column list is the best practice):
CREATE PROC dbo.GetEmployeeDepartments
AS
SELECT * FROM EMP_DEPARTMENT;
GO
The SQL Server client API will stream the result as a fast-forwared read-only resultset, where individual rows can be used.

Import DBF files into Sql Server

I need a little help figuring this out because I'm new to stored procedures. I am trying to import a .DBF table into Sql Server 2008 using this store procedure.
CREATE PROCEDURE spImportDB
-- Add the parameters for the stored procedure here
AS
BEGIN
-- Insert statements for procedure here
SELECT * into Products
FROM OPENROWSET('vfpoledb','C:\Users\Admin\Doc\Data\DBF',
'SELECT * FROM MyTable')
END
GO
I receive this error.
The OLE DB provider "vfpoledb" has not been registered.This isn't true, I've installed it and it works fine in my other application.
I've also tried running it this way with this provider but I receive this error message
Cannot initialize the data source object of OLE DB provider "Microsoft.Jet.OLEDB.4.0" for linked server "(null)".
CREATE PROCEDURE spImportDB
-- Add the parameters for the stored procedure here
AS
BEGIN
-- Insert statements for procedure here
SELECT * into Products
FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0','C:\Users\Admin\Doc\Data\DBF',
'SELECT * FROM MyTable')
END
GO
What's the easiest way to create this stored procedure? I want it to be a stored procedure not a wizard or program so please don't give me any programs.
You can try
SELECT * into SomeTable
FROM OPENROWSET('MSDASQL', 'Driver=Microsoft Visual FoxPro Driver;
SourceDB=\\SomeServer\SomePath\;
SourceType=DBF',
'SELECT * FROM SomeDBF')
from this previous question
I'm not sure about the "friendly-name" for VFPOLEDB, but the second SP should work (i.e. using 'Microsoft.Jet.OLEDB.4.0') as long as you're pointing to a specific DBF file by name. It looks like you're pointing to a directory, not the actual file.
Further information may be found in:
http://msdn.microsoft.com/en-us/library/ms190312.aspx
For anyone else looking for an answer to this, the cause of this error is installing the Foxpro driver for "Just Me" instead of "Everyone".
Run the installer for "Everyone" to avoid this error.

Resources