SQL Server openquery() with stored proc not returning data - sql

I have a stored proc that returns some data (just 1 row of dates). When I just call this proc with exec I get the returned data and all is good.
I want to make this accessible via a view so I use openquery() to do that. However when I do that I get the error message:
Cannot process the object "exec GetDates". The OLE DB provider "SQLNCLI11" for linked server "LOCAL" indicates that either the object has no columns or the current user does not have permissions on that object.
I've noticed it's the insert statement on the temp table. If I comment that out then I don't get this error. So I assume it's the permission side of that error message. It's a temp table, how can I not have permission to insert into that when I can insert into any real table in the database?
ALTER PROCEDURE [dbo].[GetDates]
AS
DECLARE #capacityTable TABLE (dt datetime)
DECLARE #dt datetime
DECLARE curDates CURSOR FOR SELECT dt from calendar;
-- loop over all dates we care about
OPEN curDates;
FETCH NEXT FROM curDates INTO #dt;
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #capacityTable (dt)
VALUES(#dt)
FETCH NEXT FROM curDates INTO #dt;
END;
CLOSE curDates;
DEALLOCATE curDates;
-- return the temp table results
SELECT dt from #capacityTable;
RETURN
alter view GetDates_vw
as
select * from openquery(LOCAL, 'exec GetDates')

It looks like before the EXEC in the openquery() function if you place SET NOCOUNT ON; it works. Not sure why but it does.

Related

How to store results of a Dynamic Query in a temp table without creating a table?

We are writing a stored procedure responsible for getting a stored procedure name and returning a result containing the stored procedure columns and their data types.
However, we bumped into a problem executing a dynamic query to return the results of stored procedure, but we can't store it in a temp table!
You can see our query below:
DECLARE #ProcName VARCHAR(100)='spGetOraganizationsList',
#ParamName VARCHAR(100),#DataType VARCHAR(20),
#Query NVARCHAR(MAX)='EXEC '+'spGetOraganizationsList '
SELECT PARAMETER_NAME,DATA_TYPE
INTO #Tmp
FROM information_schema.PARAMETERS
WHERE SPECIFIC_NAME=#ProcName
DECLARE ParamCursor CURSOR
FOR SELECT * FROM #Tmp
OPEN ParamCursor
FETCH NEXT FROM ParamCursor
INTO #ParamName,#DataType
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query=#Query+#ParamName+'=Null,'
FETCH NEXT FROM ParamCursor INTO #ParamName,#DataType
END
CLOSE ParamCursor
DEALLOCATE ParamCursor
DROP TABLE #Tmp
EXEC sp_executesql #Query
The thing is I can't store the results of it in a temp table,
and OPENROWSET does not accept variables.
I think it comes from sql concept that it doesn't trust in result of stored procedures and because of that we cannot select on it or store it in a table by 'making in query table' method.
Unless you create a table and define it's columns and sql trust to you and you insert result of it into this table for example take below situation
Create table test (name varchar(10),family varchar(20))
Insert into test
Exec sp-testResult
Now if you define wrong column for your table you will receive query runtime error .actually sql doesn't predict result of sp and leaves it to you to define result of your stored procedure.
You can certainly INSERT the results of a stored procedure into a TEMP table:
CREATE PROCEDURE PurgeMe
AS
SELECT convert(int, 1) AS DaData
UNION
SELECT convert(int, 2)
GO
CREATE TABLE #Doodles (AnInteger int)
INSERT #Doodles EXECUTE PurgeMe
SELECT * FROM #Doodles
Questions arise about the SCOPE of TEMP tables, however. You might find that in your calling routine you will not be able to see a TEMP table created within your routine.
The solution to the SCOPE problem is to do the following:
Create a minimal TEMP table (say, with one column)
Use ALTER TABLE on the TEMP table within your routine to make its schema match
your needs (this can be tricky, but it can be done)
Put data into the TEMP table
return from your routine - the calling routine will now be able to access the temp
table
If this is of interest I can make a longer post with a stored procedure to do the above. It was written to facilitate dynamic SQL
Write select query as you want in the stored procedure. You will get the result without creating temp table.
Use global temp table and dynamic OPENROWSET
DROP TABLE ##Tmp;
GO
DECLARE #ProcName VARCHAR(100)='spGetOraganizationsList',
#ParamName VARCHAR(100), #DataType VARCHAR(20),
-- Mind to specify database and schema of the SP
#Query NVARCHAR(MAX)=' EXEC [mydb].[dbo].spGetOraganizationsList ';
SELECT PARAMETER_NAME,DATA_TYPE
INTO #Tmp
FROM information_schema.PARAMETERS
WHERE SPECIFIC_NAME=#ProcName;
-- Build SP exec
DECLARE ParamCursor CURSOR
FOR SELECT * FROM #Tmp
OPEN ParamCursor
FETCH NEXT FROM ParamCursor
INTO #ParamName,#DataType
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query=#Query+#ParamName+'=Null,'
FETCH NEXT FROM ParamCursor INTO #ParamName,#DataType
END
CLOSE ParamCursor
DEALLOCATE ParamCursor
SET #Query = left(#Query, len(#Query) - 1);
-- Build ad hoc distributed query which creates ##Tmp from SP exec.
SET #Query = 'SELECT * INTO ##Tmp FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'',''' + #Query + ''')';
EXEC (#Query);
-- Created by dynamic sql `##Tmp` is availabe in the current context.
SELECT *
FROM ##Tmp;
Don't forget to enable ad hoc distributed queries first.
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
EDIT
My answer solves only one problem, storing the result of a dynamic proc call in a temp table. And there are more problems.
First, #p=null just will not compile if the type of #p is user-defined table type. You need kind of declare #t myType;
exec mySp ... ,#p=#t ....
Next is the 'cannot retrieve matadata for sp because contain dynamic query' error you commented on. Looks like you need an application, SqlClr or standalone, which would be capable to read and parse Datasets returned by procs.
Finally, if an SP contains conditional sql which can return a result set of different schema depending on parameter values, the result of all those efforts is still questionable.
In C#, you can use an SqlDataReader or a DataTable to get the results from a stored procedure without knowing the schema beforehand. If you then want to write that data to a temporary table, I think you can do that from C# (though I've never tried to do it).

HSQL Procedure returning result set from declared table

I created a stored procedure in HSQLDB. I declared a table object and inserted data in to it.How can i pass this all table data from this procedure to caller end,Which is normal java CallebleStatement.
After inserting the data, you write DECLARE CURSOR ... then OPEN ... statements. See the Guide, http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#src_psm_cursors which contains this example:
BEGIN ATOMIC
DECLARE temp_zero DATE;
DECLARE result CURSOR WITH RETURN FOR SELECT * FROM INFORMATION_SCHEMA.TABLES FOR READ ONLY;
-- more statements ...
OPEN result;
END

invalid object name #temp between rpc and sp starting

I have a stored procedure that creates some temporary tables and runs some dynamic sql using them.
I'm creating the temp tables first, then inserting into them, then running the exec(#sql) that references them.
The app I'm building that uses this proc calls it a few times in a row. I traced it, and saw something I don't understand. I'm looking at RPC:Starting, RPC:Completed, SP:Starting, SP:Completed, and Exceptions. The trace looks like this:
RPC:Starting exec my_proc
Exception Invalid object name '#temp'. --a few of these
SP:Starting exec my_proc
SP:Completed exec my_proc
RPC:Completed exec my_proc
Everything works, I'm just confused about what's going on with that exception between the RPC:Starting and SP:Starting. Could someone please explain? I was under the impression my procedure didn't start until the SP:Starting.
Edit: Timestamps for Exception, SP:Starting, and SP:StmtStarting for CREATE TABLE #temp1 (test INT) are all the same. The statement INSERT INTO #temp1..., is .003 seconds later.
The simplified version of the whole procedure is:
...AS
CREATE TABLE #temp1
(test INT)
INSERT INTO #temp1
SELECT some_numbers
FROM some_table
--Simplification, but same premise,
--Concatenate a partial statement with result from querying the #temp table
DECLARE #sql VARCHAR(MAX) =
'CREATE VIEW ['+#someName+'] AS SELECT '+SELECT test FROM #temp1+' FROM some_other_table'
DROP TABLE #temp1
BEGIN TRY
exec(#sql)
END TRY
BEGIN CATCH
END CATCH
Edit 2: Forgot to mention, this error only happens on the FIRST execution of the procedure when it's called a couple times in a row by my app.
I think the problem is that you DROP TABLE #temp1 too soon. A slightly simplified version of your code that works is the following:
CREATE TABLE #temp1
(test INT)
INSERT INTO #temp1
SELECT 1
FROM sometable
--Simplification, but same premise,
--Concatenate a partial statement with result from querying the #temp table
DECLARE #sql VARCHAR(MAX) =
'CREATE VIEW etc AS SELECT test FROM #temp1 '
BEGIN TRY
exec(#sql)
END TRY
BEGIN CATCH
END CATCH
select * from #temp1
DROP TABLE #temp1
Notice that the view has a name and DROP TABLE is moved after dynamic SQL query is executed.
There's actually nothing wrong with your code, and the error can be ignored.
It's happening because of a SQL Server feature called Deferred Name Resolution. At the time the batch is compiled, the #temp1 table doesn't exist - Profiler is reporting this. When it comes to actually executing the batch though, the table has been created and hence the stored procedure executes successfully.

SQL Selecting a list of Ids and run them through SP

I just started SQL with Microsoft SQL Server 2008 R2 and I want to select a list of Ids and run each of them through a stored procedure but am not sure how to do it.
SELECT Id
FROM UserId
WHERE ProgramId = #ProgramId
Then, I have created a procedure called temp_sp_UpdateIds
Normally I can just run the stored procedure with
EXEC temp_sp_UpdateIds #ProgramId
but I am not sure how to run the stored procedure with the list of Ids returned from the select statement and place it under #ProgramId
Do I need to store the Ids in a local table or something?
Thanks.
You can use Table-Valued Parameters
Creating a Table Type and SP
CREATE TYPE dbo.ListOfIds AS TABLE(Id int PRIMARY KEY)
GO
CREATE PROCEDURE dbo.temp_sp_UpdateIds
(
#ListOfIds dbo.ListOfIds READONLY
)
AS
BEGIN
...body of procedure
END
GO
Calling a Procedure with a Table-Valued Parameter
DECLARE #ListOfIds dbo.ListOfIds
INSERT #ListOfIds
SELECT Id
FROM UserId
WHERE ProgramId = #ProgramId
EXEC dbo.temp_sp_UpdateIds #ListOfIds
See SQLFiddle
You're unfortunately looking a cursor. Concept is you will provide your query in the first block, declare the variable(s) you'll need to operate your proc and then iterate through them.
DECLARE CSR CURSOR
READ_ONLY
FOR SELECT ProgramId FROM UserId
DECLARE #programid int
OPEN CSR
FETCH NEXT FROM CSR INTO #programid
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
EXECUTE temp_sp_UpdateIds #programId
END
FETCH NEXT FROM CSR INTO #programId
END
CLOSE CSR
DEALLOCATE CSR
GO
The other option that comes to mind is to generate the EXEC calls in SQL, concatenate all of that together with a semicolon and then exec that.
If you can change the proc to a function (that returns a value - even just null) you can simply do this:
SELECT temp_sp_UpdateIds(id) FROM UserId WHERE ProgramId=#ProgramId
In normal case you may do something like this:
SELECT * FROM UserId WHERE ProgramId in (SELECT ProgramId FROM t WHERE ...)
If procedure fill #ParamId by somthing like select result with one column - it must work

SQL INSERT INTO calling Stored Procedure instead

I would like to do something like this in SQL
Insert Into storedproc2
SELECT column1, column2 from Tablename
My goal is to have each row of data in tablename processed using the storedproc2 stored procedure, which itself handles any insertion necessary in the logic flow.
Well as others said, you can't do that on a single statement. (that's just the way things work)
If what you wan't is to call a proc with the results you can first select and then call the proc using a cursor.
The cursor would perform a row by row code and you would be able to call the proc passing the correct values. But beware cursors are slow use Flags like FAST_FORWARD.
The other way would be to change your proc to accept a whole table, as a table valued parameter, if that is possiblel, that would perform really better.
Hope this helps.
DECLARE CallingProcCursor CURSOR
FAST_FORWARD
FOR
SELECT database_id,name from sys.databases
DECLARE #database_id int, #name sysname
OPEN CallingProcCursor
FETCH NEXT FROM CallingProcCursor INTO #database_id, #name
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
EXEC PROCX #database_id, #name
END
FETCH NEXT FROM CallingProcCursor INTO #database_id, #name
END
CLOSE CallingProcCursor
DEALLOCATE CallingProcCursor
GO
You can't insert into a stored procedure. You can only insert into a table (and in some cases a view, depending on the DB platform and whether the view is updateable.)
You can use a stored procedure to insert data as shown here: http://www.codeproject.com/KB/cs/tariqaziz.aspx
This is NOT meant to be insulting, but rather helpful...
It sounds like you need to go read up on stored procedures, since your question shows that you don't get the basics.
http://databases.about.com/od/sqlserver/a/storedprocedure.htm
As David said, you can't do this the way you want.
What you CAN do is feed the stored proc a table as a parameter, and have it perform it's logic on each row in that table. It will involve some Dynamic SQL but it is doable.
you can put insert statement inside stored proc and pass the values as parameters e.g.
following is just an example, on each row you can call your stored proc and it should be fine
CREATE PROC BDD_AddMessageLogItem(
#BusinessDevelopmentItemId INT,
#MessageLog NVARCHAR(MAX),
#PostedBy SMALLINT,
#PostedOfficeId TINYINT,
#PostedDepartmentId TINYINT,
#PostedMessageLogType TINYINT)
AS
BEGIN
DECLARE #BusinessDevelopmentMessageLogId SMALLINT
INSERT INTO dbo.BusinessDevelopmentItemMessageLogs
( BusinessDevelopmentItemId ,
MessageLog ,
DatePosted,
PostedBy,
PostedOfficeId,
PostedDepartmentId,
PostedMessageLogType,
BusinessDevelopmentMessageLogId
)
VALUES ( #BusinessDevelopmentItemId , -- BusinessDevelopmentItemId - int
#MessageLog , -- Message - nvarchar(100)
GETDATE(),
#PostedBy,
#PostedOfficeId,
#PostedDepartmentId,
#PostedMessageLogType,
#BusinessDevelopmentMessageLogId
)
END
You can't pass data sets to stored procedures, only parameters. You could:
Pass the table name to the stored procedure and then construct the select.
Pass the whole query as a parameter.
And then execute it with sp_executesql. If you use this method you should read The Curse and Blessings of Dynamic SQL.