开发者

Select Values From SP And Temporary Tables

I have a Stored Procedure in MSSQL 2008, inside of this i've created a Temporary Table, and then i executed several inserts into the temporary Table. How can i select all the columns of the Temporary Table outside the stored procedure? I Mean, i have this:

CREATE PROCEDURE [dbo].[LIST_CLIENTS]

    CREATE TABLE #CLIENT(
         --Varchar And Numeric Values goes here
     )

  /*Several Select's and Insert's against the Temporary Table*/

  SELECT * FROM #CLIENT

END

In another Query i'm doing this:

sp_configure 'Show Advanced Options', 1 
GO
RECONFIGURE
GO

sp_configure 'Ad Hoc Distributed Queries', 1 
GO
RECONFIGURE
GO

    SELECT * 
    INTO #CLIENT 
    FROM OPENROWSET
    ('SQLOLEDB','Server=(local);Uid=Cnx;pwd=Cnx;database=r8;Trusted_Connection=yes;
    Integrated Security=SSPI',
    'EXEC dbo.LIST_CLIENTS ''20110602'开发者_开发问答', NULL, NULL, NULL, NULL, NULL')

But i get this error:

Msg 208, Level 16, State 1, Procedure LIST_CLIENTS, Line 43
Invalid object name '#CLIENT'.

I've tried with Global Temporary Tables and It doesn't work. I know that is the scope of the temporary table, but, how can i get the table outside the scope of the SP?

Thanks in advance


I think there is something deeper going on here.

One idea is to use a table variable inside the stored procedure instead of a #temp table (I have to assume you're using SQL Server 2005+ but it's always nice to state this up front). And use OPENQUERY instead of OPENROWSET. This works fine for me:

USE tempdb;
GO
CREATE PROCEDURE dbo.proc_x
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @x TABLE(id INT);
    INSERT @x VALUES(1),(2);
    SELECT * FROM @x;
END
GO

SELECT *
  INTO #client 
  FROM OPENQUERY
  (
    [loopback linked server name], 
    'EXEC tempdb.dbo.proc_x'
  ) AS y;

SELECT * FROM #client;

DROP TABLE #client;

DROP PROCEDURE dbo.proc_x;

Another idea is that perhaps the error is occurring even without using SELECT INTO. Does the stored procedure reference the #CLIENT table in any dynamic SQL, for example? Does it work when you call it on its own or when you just say SELECT * FROM OPENROWSET instead of SELECT INTO? Obviously, if you are working with the #temp table in dynamic SQL you're going to have the same kind of scope issue working with a @table variable in dynamic SQL.

At the very least, name your outer #temp table something other than #CLIENT to avoid confusion - then at least nobody has to guess which #temp table is not being referenced correctly.


Since the global temp table failed, use a real table, run this when you start your create script and drop the temp table once you are done to make sure.

IF OBJECT_ID('dbo.temptable', 'U') IS NOT NULL
BEGIN 
DROP TABLE dbo.temptable
END

CREATE TABLE dbo.temptable 
(    ... ) 


You need to run the two queries within the same connection and use a global temp table.


In SQL Server 2008 you can declare User-Defined Table Types which represent the definition of a table structure. Once created you can create table parameters within your procs and pass them a long and be able to access the table in other procs.


I guess the reason for such behavior is that when you call OPENROWSET from another server it firstly and separately requests the information about procedure output structure (METADATA). And the most interesting thing is that this output structure is taken from the first SELECT statement found in the procedure. Moreover, if the SELECT statement follows the IF-condition the METADATA request ignores this IF-condition, because there is no need to run the whole procedure - the first met SELECT statement is enough. (By the way, to switch off that behavior, you can include SET FMTONLY OFF in the beginning of your procedure, but this might increase the procedure execution time).

The conclusions:

— when the METADATA is being requested from a temp table (created in a procedure) it does not actually exists, because the METADATA request does not actually run the procedure and create the temp table.

— if a temp table can be replaced with a table variable it solves the problem

— if it is vital for the business to use temp table, the METADATA request can be fed with fake first SELECT statement, like:

declare @t table(ID int, Name varchar(15));
if (0 = 1) select ID, Name from @t;         -- fake SELECT statement
create table #T (ID int, Name varchar(15));
select ID, Name from #T;                    -- real SELECT statement

— and one more thing is to use a common trick with FMTONLY (that is not my idea) :

declare @fmtonlyOn bit = 0;
if 1 = 0 set @fmtonlyOn = 1;
set fmtonly off;
create table #T (ID int, Name varchar(15));      
if @fmtonlyOn = 1 set fmtonly on;
select ID, Name from #T;


The reason you're getting the error is because the temp table #Client was not declared before you ran the procedure to insert into it. If you declare the table, then execute the list proc and use direct insert -

INSERT INTO #Client

EXEC LIST_CLIENTS

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜