Выбрать значения из SP и временных таблиц - PullRequest
1 голос
/ 01 августа 2011

У меня есть хранимая процедура в MSSQL 2008, внутри которой я создал временную таблицу, а затем выполнил несколько вставок во временную таблицу. Как я могу выбрать все столбцы временной таблицы вне хранимой процедуры? Я имею в виду, у меня есть это:

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

В другом запросе я делаю это:

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')

Но я получаю эту ошибку:

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

Я пробовал использовать глобальные временные таблицы, и это не работает. Я знаю, что это область действия временной таблицы, но как я могу получить таблицу вне области действия SP?

Заранее спасибо

Ответы [ 6 ]

1 голос
/ 02 августа 2011

Я думаю, что здесь происходит что-то более глубокое.

Одна идея - использовать переменную таблицы внутри хранимой процедуры вместо таблицы #temp (я должен предположить, что вы используете SQL Server 2005+но это всегда приятно заявить об этом заранее).И используйте OPENQUERY вместо OPENROWSET.Это прекрасно работает для меня:

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;

Другая идея заключается в том, что, возможно, ошибка происходит даже без использования SELECT INTO.Ссылочная хранимая процедура ссылается на таблицу #CLIENT в каком-либо динамическом SQL, например?Работает ли он, когда вы звоните сами или просто говорите SELECT * FROM OPENROWSET вместо SELECT INTO?Очевидно, что если вы работаете с таблицей #temp в динамическом SQL, у вас возникнет такая же проблема с областью действия при работе с переменной @table в динамическом SQL.#temp table что-то отличное от #CLIENT, чтобы избежать путаницы - тогда, по крайней мере, никто не должен угадывать, на какую таблицу #temp ссылаются неправильно.

1 голос
/ 02 августа 2011

Поскольку глобальная временная таблица потерпела неудачу, используйте реальную таблицу, запустите ее при запуске сценария создания и удалите временную таблицу, как только закончите, чтобы убедиться.

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

CREATE TABLE dbo.temptable 
(    ... ) 
0 голосов
/ 20 марта 2014

Причина, по которой вы получаете ошибку, заключается в том, что временная таблица #Client не была объявлена ​​до того, как вы запустили процедуру ее вставки. Если вы объявите таблицу, выполните список процедур и используйте прямую вставку -

INSERT INTO # Клиент

EXEC LIST_CLIENTS

0 голосов
/ 02 августа 2011

Я предполагаю, что причина такого поведения в том, что когда вы вызываете OPENROWSET с другого сервера, он сначала и отдельно запрашивает информацию о структуре вывода процедуры (METADATA). И самое интересное, что эта структура вывода взята из первого оператора SELECT, найденного в процедуре. Более того, если инструкция SELECT следует условию IF, запрос METADATA игнорирует это условие IF, поскольку нет необходимости запускать всю процедуру - достаточно первого выполненного оператора SELECT. (Кстати, чтобы отключить это поведение, вы можете включить SET FMTONLY OFF в начале вашей процедуры, но это может увеличить время выполнения процедуры).

Выводы:

- когда METADATA запрашивается из временной таблицы (созданной в процедуре), она фактически не существует, поскольку запрос METADATA фактически не запускает процедуру и не создает временную таблицу.

- если временная таблица может быть заменена табличной переменной, это решает проблему

- если для бизнеса жизненно важно использовать временную таблицу, запрос METADATA можно передать с помощью поддельной first инструкции SELECT, например:

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

- и еще одна вещь - использовать общий прием с FMTONLY (это не моя идея):

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;
0 голосов
/ 02 августа 2011

В SQL Server 2008 вы можете объявить определяемые пользователем типы таблиц , которые представляют собой определение структуры таблицы.После создания вы можете создавать параметры таблицы в своих процессах и передавать их длинным и иметь возможность доступа к таблице в других процессах.

0 голосов
/ 02 августа 2011

Вам необходимо выполнить два запроса в одном соединении и использовать глобальную временную таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...