Вставте результати збереженої процедури у тимчасову таблицю


1577

Як це зробити SELECT * INTO [temp table] FROM [stored procedure]? Не FROM [Table]і без визначення [temp table]?

Selectвсі дані BusinessLineв tmpBusLineвідмінно працює.

select *
into tmpBusLine
from BusinessLine

Я намагаюсь те саме, але використання a, stored procedureщо повертає дані, не зовсім те саме.

select *
into tmpBusLine
from
exec getBusinessLineHistory '16 Mar 2009'

Вихідне повідомлення:

Msg 156, рівень 15, стан 1, рядок 2 Неправильний синтаксис біля ключового слова "exec".

Я прочитав кілька прикладів створення тимчасової таблиці з тією ж структурою, що і вихідна збережена процедура, яка працює чудово, але було б непогано не надавати жодних стовпців.


22
За допомогою SELECT * INTO [TABLE NAME] ви знаєте стовпці, оскільки вони скопійовані з вихідної таблиці. Це саме те, що я хочу, якби я робив те ж саме проти збереженої процедури.
Фердін


7
Просто хочу зазначити, що "select * into tmpBusLine" створює постійну таблицю. Ви, мабуть, хочете "вибрати * у #tmpBusLine". Я впевнений, що оригінальний плакат уже знайшов це, але це може допомогти іншим, хто знайде цю публікацію, оскільки це найвищий результат на даний момент для пошуку "вибрати в таблицю темпів"
ktam33

2
Я не знаю, чи вирішено це чи ні, але причина, чому ви отримуєте помилку, пов’язана з ключовим словом.
Уес Палмер

9
Microsoft має додати SELECT * ДО EXEC! Будь ласка!
kjmerf

Відповіді:


704

Для цього можна використовувати OPENROWSET . Гляньте. Я також включив код sp_configure, щоб увімкнути розповсюджені запити Ad Hoc, якщо він ще не ввімкнено.

CREATE PROC getBusinessLineHistory
AS
BEGIN
    SELECT * FROM sys.databases
END
GO

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

SELECT * INTO #MyTempTable FROM OPENROWSET('SQLNCLI', 'Server=(local)\SQL2008;Trusted_Connection=yes;',
     'EXEC getBusinessLineHistory')

SELECT * FROM #MyTempTable

28
Це правильний спосіб зробити це. OPENROWSET - це майже єдиний спосіб трактувати результати збереженої процедури як вираз таблиці.
Роб Фарлі

37
Це здається трохи громіздким просто вставити в стіл. Дуже багато налаштування. Також коли я спробував це, я отримав "Msg 7357, рівень 16, стан 2, рядок 1 Не вдається обробити об'єкт" EXEC GetPartyAnalysisData 146 ". Провайдер OLE DB" SQLNCLI "для пов'язаного сервера" (null) "вказує, що будь-який об'єкт має жодні стовпці або поточний користувач не мають дозволів на цей об’єкт. " Тож вам потрібно встановити пов'язаний сервер ...
Фердін

10
Вам не потрібен зв'язаний сервер, але вам потрібно буде правильно встановити рядок з'єднання ... а також вказати повний шлях до збереженої процедури, включаючи ім'я бази даних та власника sp.
MartW

18
eeeeew! посилання на той же сервер? бридкий. напевно більше хака, ніж вручну створювати таблицю темпів
Тім Абел

23
Я згоден, що це злом, і, ймовірно, його слід уникати, якщо ваша спина не буде прилягати до стіни. Зміна sp на функцію - це, мабуть, кращий кут. ІМХО.
greg

623

Якщо ви хочете зробити це без попереднього оголошення тимчасової таблиці, ви можете спробувати створити визначену користувачем функцію, а не збережену процедуру, і зробити так, щоб визначена користувачем функція повертала таблицю. Якщо ви хочете використовувати збережену процедуру, спробуйте щось подібне:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

170
Думаю, суть полягала в тому, щоб генерувати схему без явного декларування.
Крейг

5
Мені було б цікаво дізнатись, у чому різниця між цим рішенням та рішенням @Aaron Alton. Це здається набагато простішим, але я не впевнений у будь-яких інших наслідках.
funkymushroom

11
Це буде працювати, але якщо ви коли-небудь додасте додаткові стовпці до збереженої процедури SpGetRecords, це підірветься.
Брейді Холт

15
Ви отримуєте лише одну ВСТАВЛЮВАННЯ В ЕКЕКС за стек дзвінків SpGetRecords та будь-яка інша програма, яку він викликає, можуть не використовувати цю стратегію у власному коді. Це може здивувати підтримання SpGetRecords.
Метт Стівенсон

33
Це взагалі не відповідає на питання, і я не бачу, чому це так схвалено? ОП чітко вказано "без визначення [таблиця темпів]", і ваш перший рядок має оператор створення таблиці темп.
NickG

296

У SQL Server 2005 ви можете використовувати INSERT INTO ... EXECдля вставки результату збереженої процедури в таблицю. З документації MSDNINSERT (фактично для SQL Server 2000):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales

122
Для цього потрібно визначити авторів продавців спереду. Я намагаюся цього уникнути. Дякую.
Фердін

5
Я так само думав. Настільки корисне Вставлення в таблицю tmp під час руху, але не настільки корисно, якщо вам потрібно знати структуру набору даних, повернуту із збереженої програми. Дякую за допомогу.
Фердін

3

4
Для того, щоб використовувати ту ж схему, ви можете зробити копію наступним чином : виберіть верхній 0 * в TempTable з realTable ( stackoverflow.com/a/9206463/73794 )
Навіть Mien

@EvenMien Я на мить збудився, побачивши ваш коментар ... але, на жаль, працює лише в тому випадку, якщо результати вашої профспілки насправді відображають реальну таблицю :(
BVernon,

193

Це відповідь на дещо змінену версію вашого питання. Якщо ви можете відмовитися від використання збереженої процедури для визначеної користувачем функції, ви можете використовувати функцію вбудованої таблиці, оцінену користувачем. Це по суті збережена процедура (буде приймати параметри), яка повертає таблицю як набір результатів; і тому буде гарно розміщено із заявою INTO.

Ось хороша коротка стаття про нього та інші визначені користувачем функції. Якщо у вас все ще виникає потреба у рушії для збереженої процедури, ви можете обернути вбудовану функцію, визначену користувачем, збережену процедуру. Збережена процедура просто передає параметри, коли вона викликає select * з функції вбудованої таблиці, оціненої користувачем.

Так, наприклад, у вас є функція вбудованої таблиці, що визначається користувачем, щоб отримати список клієнтів для певного регіону:

CREATE FUNCTION CustomersByRegion 
(  
    @RegionID int  
)
RETURNS TABLE 
AS
RETURN 
  SELECT *
  FROM customers
  WHERE RegionID = @RegionID
GO

Потім ви можете зателефонувати за допомогою цієї функції, щоб отримати такі результати:

SELECT * FROM CustomersbyRegion(1)

Або зробити ВИБІР ВІД:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Якщо вам все-таки потрібна збережена процедура, оберніть функцію як таку:

CREATE PROCEDURE uspCustomersByRegion 
(  
    @regionID int  
)
AS
BEGIN
     SELECT * FROM CustomersbyRegion(@regionID);
END
GO

Я думаю, що це найбільш "безрезультатний" метод для отримання бажаних результатів. Він використовує існуючі функції так, як вони були призначені для використання без додаткових ускладнень. Вклавши функцію вбудованої таблиці, що визначається користувачем, у збереженій процедурі, ви маєте доступ до функціональності двома способами. Плюс! У вас є лише один пункт обслуговування фактичного коду SQL.

Запропоновано використання OPENROWSET, але це не те, для чого функція OPENROWSET повинна була використовуватися (із книг Інтернет):

Включає всю інформацію про з'єднання, необхідну для доступу до віддалених даних із джерела даних OLE DB. Цей метод є альтернативою доступу до таблиць на пов'язаному сервері та є разовим, спеціальним методом підключення та доступу до віддалених даних за допомогою OLE DB. Для частіших посилань на джерела даних OLE DB замість цього використовуйте пов'язані сервери.

Використання OPENROWSET дозволить виконати роботу, але це матиме додаткові накладні витрати для відкриття локальних з'єднань та даних щодо маршового обміну. Він також не може бути варіантом у всіх випадках, оскільки для нього потрібен дозвіл на спеціальний запит, який становить загрозу безпеці, а тому може бути не бажаним. Також підхід OPENROWSET виключатиме використання збережених процедур, повертаючи більше одного набору результатів. Об'єднання декількох вбудованих табличних значень функцій, визначених користувачем, в одній збереженій процедурі може досягти цього.


4
+1 Функція на основі таблиці - це відповідне рішення. Слід зазначити незначні недоліки: функція, що оцінюється за таблицею, є додатковим об’єктом бази даних, і, можливо, буде потрібно надати привілеї на неї.
spencer7593

2
Любіть рішення. Один незначний забій, який я потрапив, - це те, що мій стіл не може мати порядок там, де він міг би його мати в збереженій процедурі. О, добре, я розберу це
mrwaim

5
Ще один корч - "Неможливо отримати доступ до тимчасових таблиць у межах функції"
mrwaim

7
Оригінальне питання полягає в тому, як ми створюємо тимчасову таблицю з результатами sp. Це гарна модель, але все ж не вирішуйте це питання
greg

16
Грег, перший рядок моєї відповіді зазначає "Це відповідь на дещо змінену версію вашого питання". Ваш коментар є зайвим.
Крістіан Лоріс

131
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

SELECT  *
INTO    #tmpTable
FROM    OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')

2
Отримайте "Msg 208, рівень 16, стан 1, рядок 1 Недійсне ім'я об'єкта" tmpBusLine "(можливо, так, як це не визначено вперед).
Фердін,

1
@Ferds: вибачте, спочатку не зрозумів ваш запит. Оновлено іншим рішенням.
Quassnoi

26
Прекрасне рішення. Один застереження, вам потрібно буде включити "ДОСТУП ДАНИХ" на вашому сервері: EXEC sp_serveroption 'TheServerName', 'DATA ACCESS', TRUE
jcollum

8
Вам також потрібно дозволити віддалений доступ до сервера. Це матиме наслідки для безпеки.
BraveNewMath

7
Це не буде працювати , якщо цільова збережена процедура використовує тимчасові таблиці
Sal

125

Найпростіше рішення:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Якщо ви не знаєте схеми, ви можете зробити наступне. Зауважте, що у цього методу є серйозні ризики для безпеки.

SELECT * 
INTO #temp
FROM OPENROWSET('SQLNCLI', 
                'Server=localhost;Trusted_Connection=yes;', 
                'EXEC [db].[schema].[sproc]')

якщо я не знаю стовпець повернутого набору результатів, то ??? я маю на увазі стовпець може змінюватися. так як вставити результат у таблицю темп ???
ШЕХАР ШЕЙТ

Ви можете використовувати OPENQUERY, але це не рекомендується, оскільки воно має недоліки в безпеці.
Tigerjz32

1
"якщо я не знаю стовпець повернутого набору результатів, то", то ви не можете використовувати його у своїй логіці. Як ви будете використовувати дані, якщо не знаєте, що це?
Адріан Давел

@AdriaanDavel Я погоджуюся з вами, що ви завжди повинні знати свої дані (найкраща практика), однак, що він може сказати, це те, що бувають випадки, коли проросток повертає динамічні стовпці, і ви не завжди знаєте, як виглядатиме схема. У цьому випадку ви можете використовувати OPENROWSET для вставки та створення таблиці на льоту. Однак при цьому є очевидні ризики для безпеки ...
Tigerjz32

1
@nurettin іноді ви не знаєте, що зберігається процедура повертається. Що відбувається в такому випадку? Як ви могли створити таблицю тимчасових тем (коли ви не знаєте, що повертається збережена процедура) і вставити в неї зі збереженої процедури?
Tigerjz32

106

Коли збережена процедура повертає багато стовпців, і ви не хочете вручну "створити" тимчасову таблицю для проведення результату, я знайшов найпростіший спосіб - перейти до збереженої процедури та додати пункт "в" на останній оператор select і додайте 1 = 0 до пункту де.

Запустіть збережену процедуру один раз і поверніться та видаліть щойно доданий вами SQL-код. Тепер у вас буде порожня таблиця, що відповідає результату збереженої процедури. Ви можете або "таблицю сценаріїв як створити" для тимчасової таблиці, або просто вставити безпосередньо в цю таблицю.


9
+1, відмінна пропозиція. Ви навіть можете додати швидку необов’язкову змінну до паростка під назвою @TableCreate або щось подібне, що, коли немає нуля, виконайте дії, описані вище. Не вимагає зміни паростки після її встановлення.
Ян Рок

1
@dotjoe Ви робите SELECT INTOтимчасову таблицю і робите таблицю сценаріїв, як створюєте з таблиці темп? Таблиці темп відображаються, tempdbале я не в змозі зробити клацання правою кнопкою миші та створити сценарій створення. Будь-яка допомога вдячна.
DotnetDude

2
@DotNetDude ви можете select ... into new_tableнеявно створити фактичну таблицю.
dotjoe

Потім схопіть грубе визначення стовпця із схеми порожньої таблиці; в кінці замініть "..." на законний TABLE_NAME:declare @s varchar(max)='';select @s=@s+','+COLUMN_NAME+' '+DATA_TYPE+isnull('('+case CHARACTER_MAXIMUM_LENGTH when -1 then 'max' else cast(CHARACTER_MAXIMUM_LENGTH as varchar(10))end+')','')from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='...';select @s
user423430

Це найкраще рішення!
Лукас925

66
declare @temp table
(
    name varchar(255),
    field varchar(255),
    filename varchar(255),
    filegroup varchar(255),
    size varchar(255),
    maxsize varchar(255),
    growth varchar(255),
    usage varchar(255)
);
INSERT @temp  Exec sp_helpfile;
select * from @temp;

3
не стосується оригінального питання OP, виконуючи вставку із визначенням спочатку таблиці темп.
вторник

48

Чи збережена вами процедура лише отримує дані чи також їх змінює? Якщо він використовується лише для отримання, ви можете перетворити збережену процедуру у функцію та використовувати загальні вирази таблиці (CTE), не оголошуючи її, як описано нижче:

with temp as (
    select * from dbo.fnFunctionName(10, 20)
)
select col1, col2 from temp

Однак все, що потрібно отримати з CTE, слід використовувати лише в одній заяві. Ви не можете зробити це with temp as ...і спробувати використовувати його через пару рядків SQL. Ви можете мати кілька CTE в одному операторі для більш складних запитів.

Наприклад,

with temp1020 as (
    select id from dbo.fnFunctionName(10, 20)
),
temp2030 as (
    select id from dbo.fnFunctionName(20, 30)
)
select * from temp1020 
where id not in (select id from temp2030)

1
Це не тимчасові таблиці, це CTE. technet.microsoft.com/en-us/library / ...
yucer

5
Дякую @yucer ... Я вважаю, що тоді я не знав, що їх називали CTEs :)
Так користувач

48

Якщо таблиця результатів збереженого процесора є надто складною для введення вручну оператора "створення таблиці", і ви не можете використовувати OPENQUERY OR OPENROWSET, ви можете використовувати sp_help для створення списку стовпців і типів даних для вас. Після того, як у вас з’явиться список стовпців, це просто питання відформатувати його під свої потреби.

Крок 1: Додайте "у #temp" до вихідного запиту (наприклад, "виберіть [...] у #temp з [...]").

Найпростіший спосіб - це редагувати вихідний запит безпосередньо в процедурі. якщо ви не можете змінити збережену програму, ви можете скопіювати вміст у нове вікно запиту та змінити його.

Крок 2: Запустіть sp_help на таблиці темп. (наприклад, "exec tempdb..sp_help #temp")

Після створення таблиці темпів запустіть sp_help на таблиці темп, щоб отримати список стовпців і типів даних, включаючи розмір полів varchar.

Крок 3: Скопіюйте стовпці та типи даних у оператор створення таблиці

У мене є лист Excel, який я використовую для форматування виводу sp_help у операторі "створити таблицю". Вам не потрібно нічого фантазійного, просто скопіюйте та вставте у свій редактор SQL. Використовуйте назви, розміри та типи стовпців для побудови оператора "Створити таблицю #x [...]" або "оголосити таблицю @x [...]", який можна використовувати для ВСТАВКИ результатів збереженої процедури.

Крок 4: Вставте в щойно створену таблицю

Тепер у вас з’явиться запит, подібний до інших рішень, описаних у цій темі.

DECLARE @t TABLE 
(
   --these columns were copied from sp_help
   COL1 INT,
   COL2 INT   
)

INSERT INTO @t 
Exec spMyProc 

Цей прийом можна також використовувати для перетворення тимчасової таблиці ( #temp) у змінну таблиці ( @temp). Хоча це може бути більше кроків, ніж просто написати create tableзаяву самостійно, це запобігає помилкам вручну, таким як помилки друку та типу даних у великих процесах. Налагодження помилки друку може зайняти більше часу, ніж написання запиту.


37

Якщо OPENROWSET викликає у вас проблеми, є ще один спосіб з 2012 року; скористайтеся sys.dm_exec_describe_first_result_set_for_object, як згадується тут: Отримати назви стовпців та типи збереженої процедури?

Спочатку створіть цю збережену процедуру для генерації SQL для тимчасової таблиці:

CREATE PROCEDURE dbo.usp_GetStoredProcTableDefinition(
    @ProcedureName  nvarchar(128),
    @TableName      nvarchar(128),
    @SQL            nvarchar(max) OUTPUT
)
AS
SET @SQL = 'CREATE TABLE ' + @tableName + ' ('

SELECT @SQL = @SQL + '['+name +'] '+ system_type_name +''  + ','
        FROM sys.dm_exec_describe_first_result_set_for_object
        (
          OBJECT_ID(@ProcedureName), 
          NULL
        );

--Remove trailing comma
SET @SQL = SUBSTRING(@SQL,0,LEN(@SQL))    
SET @SQL =  @SQL +')'

Щоб скористатися процедурою, зателефонуйте їй таким чином:

DECLARE     @SQL    NVARCHAR(MAX)

exec dbo.usp_GetStoredProcTableDefinition
    @ProcedureName='dbo.usp_YourProcedure',
    @TableName='##YourGlobalTempTable',@SQL = @SQL OUTPUT

INSERT INTO ##YourGlobalTempTable
EXEC    [dbo].usp_YourProcedure

select * from ##YourGlobalTempTable

Зауважте, що я використовую глобальну тимчасову таблицю. Це тому, що використання EXEC для запуску динамічного SQL створює власний сеанс, тому звичайна тимчасова таблиця не виходить за рамки будь-якого наступного коду. Якщо глобальна тимчасова таблиця є проблемою, ви можете використовувати звичайну тимчасову таблицю, але будь-який наступний SQL повинен бути динамічним, тобто виконаним також оператором EXEC.


4
Ви забули створити таблицю з @SQL.
Trisped

32

Quassnoi проклав мене більшу частину шляху, але одного не було:

**** Мені потрібно було використовувати параметри у збереженій процедурі. ****

І ВІДКРИТТЯ не дозволяє цього статися:

Тож я знайшов спосіб працювати з системою, а також не повинен робити визначення таблиці настільки жорстким і переосмислювати його всередині іншої збереженої процедури (і звичайно ризикувати, що вона може зламатися)!

Так, ви можете динамічно створити визначення таблиці, повернене із збереженої процедури, використовуючи оператор OPENQUERY з фальшивими змінними (доки NO RESULT SET повертає таку ж кількість полів і в тому ж самому положенні, що і набір даних з хорошими даними).

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


І щоб зазначити (як зазначено вище), ви повинні ввімкнути доступ до даних,

EXEC sp_serveroption 'MYSERVERNAME', 'DATA ACCESS', TRUE

Код:

declare @locCompanyId varchar(8)
declare @locDateOne datetime
declare @locDateTwo datetime

set @locDateOne = '2/11/2010'
set @locDateTwo = getdate()

--Build temporary table (based on bogus variable values)
--because we just want the table definition and
--since openquery does not allow variable definitions...
--I am going to use bogus variables to get the table defintion.

select * into #tempCoAttendanceRpt20100211
FROM OPENQUERY(DBASESERVER,
  'EXEC DATABASE.dbo.Proc_MyStoredProc 1,"2/1/2010","2/15/2010 3:00 pm"')

set @locCompanyId = '7753231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

set @locCompanyId = '9872231'

insert into #tempCoAttendanceRpt20100211
EXEC DATABASE.dbo.Proc_MyStoredProc @locCompanyId,@locDateOne,@locDateTwo

select * from #tempCoAttendanceRpt20100211
drop table #tempCoAttendanceRpt20100211

Дякую за інформацію, яка була надана спочатку ... Так, нарешті, мені не потрібно створювати всі ці помилкові (суворі) таблиці таблиці під час використання даних із іншої збереженої процедури чи бази даних, і так, ви також можете використовувати параметри.

Шукати довідкові теги:

  • Збережена процедура SQL 2005 в темп таблиці

  • openquery із збереженою процедурою та змінними 2005

  • openquery зі змінними

  • виконати збережену процедуру в темп таблиці

Оновлення: це не працюватиме з тимчасовими таблицями, тому мені довелося вдатися до створення тимчасової таблиці вручну.

Зауваження про помилку : це не працюватиме з тимчасовими таблицями , http://www.sommarskog.se/share_data.html#OPENQUERY

Довідка. Наступне - визначити LOCALSERVER. Це може виглядати як ключове слово в прикладі, але насправді це лише назва. Ось як ви це робите:

sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                   @provider = 'SQLOLEDB', @datasrc = @@servername

Щоб створити зв'язаний сервер, ви повинні мати дозвіл ВСІМ СЛУЖБУ або бути членом будь-якої з фіксованих ролей сервера sysadmin або setupadmin.

OPENQUERY відкриває нове підключення до SQL Server. Це має певні наслідки:

Процедура, яку ви викликаєте за допомогою OPENQUERY, не може посилатися на тимчасові таблиці, створені в поточному з'єднанні.

Нове з'єднання має власну базу даних за замовчуванням (визначено sp_addlinkedserver, за замовчуванням - головний), тому вся специфікація об'єкта повинна містити ім'я бази даних.

Якщо у вас є відкрита транзакція і ви тримаєте блокування під час виклику OPENQUERY, викликана процедура не може отримати доступ до того, що ви блокуєте. Тобто, якщо ви не будете обережні, ви заблокуєте себе.

Підключення не є безкоштовним, тому існує штраф за продуктивність.


1
Якщо ви не знаєте імені свого сервера, використовуйте SELECT @@SERVERNAME. Ви також можете скористатисяEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Контанго

24

Якщо вам пощастило мати SQL 2012 або новішої версії, ви можете використовувати dm_exec_describe_first_result_set_for_object

Я щойно відредагував sql, наданий gotqn. Спасибі gotqn.

Це створює глобальну таблицю темпів з ім'ям, таким же, як ім'я процедури. Пізніше таблицю темпів можна використовувати за потребою. Просто не забудьте скинути його перед повторним виконанням.

    declare @procname nvarchar(255) = 'myProcedure',
            @sql nvarchar(max) 

    set @sql = 'create table ##' + @procname + ' ('
    begin
            select      @sql = @sql + '[' + r.name + '] ' +  r.system_type_name + ','
            from        sys.procedures AS p
            cross apply sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r
            where       p.name = @procname

            set @sql = substring(@sql,1,len(@sql)-1) + ')'
            execute (@sql)
            execute('insert ##' + @procname + ' exec ' + @procname)
    end

1
Відмінно! Лише одне зауваження: використовуйте sys.all_objectsзамість, sys.proceduresякщо ви хочете зробити це для вбудованих збережених процедур.
Герт Арнольд

2
Це також не вдасться, якщо SP використовує тимчасові таблиці всередині нього. (але досить зручно мати це у складі арсеналу)
Трубс

23

Ця збережена програма виконує завдання:

CREATE PROCEDURE [dbo].[ExecIntoTable]
(
    @tableName          NVARCHAR(256),
    @storedProcWithParameters   NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @driver         VARCHAR(10)
    DECLARE @connectionString   NVARCHAR(600)
    DECLARE @sql            NVARCHAR(MAX)
    DECLARE @rowsetSql      NVARCHAR(MAX)

    SET @driver = '''SQLNCLI'''

    SET @connectionString = 
        '''server=' + 
            CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(256)) + 
            COALESCE('\' + CAST(SERVERPROPERTY('InstanceName') AS NVARCHAR(256)), '') + 
        ';trusted_connection=yes'''

    SET @rowsetSql = '''EXEC ' + REPLACE(@storedProcWithParameters, '''', '''''') + ''''

    SET @sql = '
SELECT
    *
INTO 
    ' + @tableName + ' 
FROM
    OPENROWSET(' + @driver + ',' + @connectionString + ',' + @rowsetSql + ')'

    EXEC (@sql)
END
GO

Це невелика переробка цього: Вставте збережені результати процедури в таблицю, щоб вона фактично працювала.

Якщо ви хочете, щоб він працював з тимчасовою таблицею, тоді вам потрібно буде використовувати ##GLOBALтаблицю і опустити її згодом.


17

Для того, щоб вставити перший набір записів збереженої процедури у тимчасову таблицю, ви повинні знати наступне:

  1. лише тимчасовий набір збережених процедур може бути вставлений у тимчасову таблицю
  2. збережена процедура не повинна виконувати динамічний оператор T-SQL ( sp_executesql)
  3. потрібно спочатку визначити структуру тимчасової таблиці

Вищезазначене може виглядати як обмеження, але IMHO це цілком має сенс - якщо ви використовуєте, sp_executesqlви можете один раз повернути два стовпці та один раз десять, а якщо у вас є кілька наборів результатів, ви також не можете вставити їх у кілька таблиць - ви можете вставити максимум у двох таблицях в одному операторі T-SQL (з використанням OUTPUTпункту та жодних тригерів).

Отже, головним питанням є те, як визначити структуру тимчасової таблиці перед виконанням EXEC ... INTO ...оператора.

Перший працює з, OBJECT_IDтоді як другий і третій також працює з спеціальними запитами. Я вважаю за краще використовувати DMV замість sp, оскільки ви можете використовувати CROSS APPLYта будувати визначення тимчасової таблиці для декількох процедур одночасно.

SELECT p.name, r.* 
FROM sys.procedures AS p
CROSS APPLY sys.dm_exec_describe_first_result_set_for_object(p.object_id, 0) AS r;

Також зверніть увагу на system_type_nameполе, оскільки це може бути дуже корисно. Тут зберігається повне визначення стовпця. Наприклад:

smalldatetime
nvarchar(max)
uniqueidentifier
nvarchar(1000)
real
smalldatetime
decimal(18,2)

і ви можете використовувати його безпосередньо в більшості випадків для створення визначення таблиці.

Отже, я думаю, що в більшості випадків (якщо збережена процедура відповідає певним критеріям) ви можете легко створити динамічні оператори для вирішення таких питань (створити тимчасову таблицю, вставити в неї результат збереженої процедури, зробити все, що вам потрібно з даними) .


Зауважте, що вищезазначені об'єкти не визначають дані першого набору результатів у деяких випадках, наприклад, коли виконуються динамічні оператори T-SQL або використовуються тимчасові таблиці в збереженій процедурі.


практичне спостереження за обмеженнями: якщо вам потрібно вставити вихід деякого sp (дозволить назвати його SP_LEVEL_0), щоб таблиця темп, динамічно створена за допомогою вищезазначеного підходу в іншому sp (дозволяє називати це SP_LEVEL_1), ви не можете зробити той самий трюк для виведення цього SP_LEVEL_1 до ще одна темп-таблиця в SP_LEVEL_2
16:00

17
  1. Я створюю таблицю з наступною схемою та даними.
  2. Створіть збережену процедуру.
  3. Тепер я знаю, що є результатом моєї процедури, тому я виконую наступний запит.

    CREATE TABLE [dbo].[tblTestingTree](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [ParentId] [int] NULL,
        [IsLeft] [bit] NULL,
        [IsRight] [bit] NULL,
    CONSTRAINT [PK_tblTestingTree] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    SET IDENTITY_INSERT [dbo].[tblTestingTree] ON
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (1, NULL, NULL, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (2, 1, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (3, 1, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (4, 2, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (5, 2, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (6, 3, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (7, 3, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (8, 4, 1, NULL)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (9, 4, NULL, 1)
    INSERT [dbo].[tblTestingTree] ([Id], [ParentId], [IsLeft], [IsRight]) VALUES (10, 5, 1, NULL)
    
    SET IDENTITY_INSERT [dbo].[tblTestingTree] OFF

    ЦІННОСТІ (10, 5, 1, NULL) Встановити IDENTITY_INSERT [dbo]. [TblTestingTree] увімкнено

    create procedure GetDate
    as
    begin
        select Id,ParentId from tblTestingTree
    end
    
    create table tbltemp
    (
        id int,
        ParentId int
    )
    insert into tbltemp
    exec GetDate
    
    select * from tbltemp;

15

Якщо запит не містить параметра, використовуйте OpenQueryінше використання OpenRowset.

Основне - створити схему відповідно до збереженої процедури та вставити її в цю таблицю. наприклад:

DECLARE @abc TABLE(
                  RequisitionTypeSourceTypeID INT
                , RequisitionTypeID INT
                , RequisitionSourcingTypeID INT
                , AutoDistOverride INT
                , AllowManagerToWithdrawDistributedReq INT
                , ResumeRequired INT
                , WarnSupplierOnDNRReqSubmission  INT
                , MSPApprovalReqd INT
                , EnableMSPSupplierCounterOffer INT
                , RequireVendorToAcceptOffer INT
                , UseCertification INT
                , UseCompetency INT
                , RequireRequisitionTemplate INT
                , CreatedByID INT
                , CreatedDate DATE
                , ModifiedByID INT
                , ModifiedDate DATE
                , UseCandidateScheduledHours INT
                , WeekEndingDayOfWeekID INT
                , AllowAutoEnroll INT
                )
INSERT INTO @abc
EXEC [dbo].[usp_MySp] 726,3
SELECT * FROM @abc

13

Код

CREATE TABLE #T1
(
    col1 INT NOT NULL,
    col2 NCHAR(50) NOT NULL,
    col3 TEXT NOT NULL,
    col4 DATETIME NULL,
    col5 NCHAR(50) NULL,
    col6 CHAR(2) NULL,
    col6 NCHAR(100) NULL,
    col7 INT NULL,
    col8 NCHAR(50) NULL,
    col9 DATETIME NULL,
    col10 DATETIME NULL
)

DECLARE @Para1 int
DECLARE @Para2 varchar(32)
DECLARE @Para3 varchar(100)
DECLARE @Para4 varchar(15)
DECLARE @Para5 varchar (12)
DECLARE @Para6 varchar(1)
DECLARE @Para7 varchar(1)


SET @Para1 = 1025
SET @Para2 = N'6as54fsd56f46sd4f65sd'
SET @Para3 = N'XXXX\UserName'
SET @Para4 = N'127.0.0.1'
SET @Para5 = N'XXXXXXX'
SET @Para6 = N'X'
SET @Para7 = N'X'

INSERT INTO #T1
(
    col1,
    col2,
    col3,
    col4,
    col5,
    col6,
    col6,
    col7,
    col8,
    col9,
    col10,
)
EXEC [dbo].[usp_ProcedureName] @Para1, @Para2, @Para3, @Para4, @Para5, @Para6, @Para6

Я сподіваюся, що це допомагає. Будь ласка, кваліфікуйте, як це потрібно.


11

Я знайшов передавання масивів / таблиць даних у збережені процедури, що може дати вам інше уявлення про те, як ви можете вирішити свою проблему.

Посилання пропонує використовувати параметр типу зображення для переходу до збереженої процедури. Потім у збереженій процедурі зображення перетворюється на змінну таблиці, що містить вихідні дані.

Можливо, є спосіб, яким це можна використовувати з тимчасовою таблицею.


4
Це більше не потрібно у версіях Sql2008 та пізніших версіях із впровадженням параметрів таблиці . Тепер ви можете безпосередньо передати .net набір даних або об’єкт даних у збережену процедуру sql, з тим, щоб зробити перетворення в байт, як зазначено у вищенаведеному посиланні
EndlessSpace

10

Я зустрів ту саму проблему, і ось що я зробив для цього з пропозицій Павла . Основна частина тут полягає у використанні, NEWID()щоб уникнути того, як багато користувачів одночасно запускають процедури / сценарії магазину, болі за глобальну тимчасову таблицю.

DECLARE @sql varchar(max) = '', 
@tmp_global_table varchar(255) = '##global_tmp_' + CONVERT(varchar(36), NEWID())
SET @sql = @sql + 'select * into [' + @tmp_global_table + '] from YOURTABLE'
EXEC(@sql)

EXEC('SELECT * FROM [' + @tmp_global_table + ']')

9

Інший метод - створити тип і використовувати PIPELINED, щоб потім повернути ваш об'єкт. Однак це обмежується знанням стовпців. Але це має перевагу в можливості:

SELECT * 
FROM TABLE(CAST(f$my_functions('8028767') AS my_tab_type))

Що це? Здається, це не має нічого спільного з SQL Server, про який йдеться у цьому питанні
Мартін Сміт

8

Це простий двошаговий процес: - створити тимчасову таблицю - вставити у тимчасову таблицю.

Код для виконання того ж:

CREATE TABLE #tempTable (Column1 int, Column2 varchar(max));
INSERT INTO #tempTable 
EXEC [app].[Sproc_name]
@param1 = 1,
@param2 =2;

Захищений; дуже схожий на існуючі відповіді.
iokevins

6

Після пошуку я знайшов спосіб динамічно створити темп-таблицю для будь-якої збереженої процедури без використання OPENROWSETабо OPENQUERYвикористання загальної схеми визначення результату збереженої процедури, особливо коли ви не адміністратор бази даних.

Сервер Sql має вбудовану програму, sp_describe_first_result_setяка може надати вам схему будь-якого набору результатів процедур. Я створив таблицю схем з результатів цієї процедури і вручну встановив усе поле NULLABLE.

declare @procname varchar(100) = 'PROCEDURENAME' -- your procedure name
declare @param varchar(max) = '''2019-06-06''' -- your parameters 
declare @execstr nvarchar(max) = N'exec ' + @procname
declare @qry nvarchar(max)

-- Schema table to store the result from sp_describe_first_result_set.
create table #d
(is_hidden  bit  NULL, column_ordinal   int  NULL, name sysname NULL, is_nullable   bit  NULL, system_type_id   int  NULL, system_type_name nvarchar(256) NULL,
max_length  smallint  NULL, precision   tinyint  NULL,  scale   tinyint  NULL,  collation_name  sysname NULL, user_type_id  int NULL, user_type_database    sysname NULL,
user_type_schema    sysname NULL,user_type_name sysname NULL,assembly_qualified_type_name   nvarchar(4000),xml_collection_id    int NULL,xml_collection_database    sysname NULL,
xml_collection_schema   sysname NULL,xml_collection_name    sysname NULL,is_xml_document    bit  NULL,is_case_sensitive bit  NULL,is_fixed_length_clr_type  bit  NULL,
source_server   sysname NULL,source_database    sysname NULL,source_schema  sysname NULL,source_table   sysname NULL,source_column  sysname NULL,is_identity_column bit NULL,
is_part_of_unique_key   bit NULL,is_updateable  bit NULL,is_computed_column bit NULL,is_sparse_column_set   bit NULL,ordinal_in_order_by_list   smallint NULL,
order_by_list_length    smallint NULL,order_by_is_descending    smallint NULL,tds_type_id   int  NULL,tds_length    int  NULL,tds_collation_id  int NULL,
tds_collation_sort_id   tinyint NULL)


-- Get result set definition of your procedure
insert into #d
EXEC sp_describe_first_result_set @exestr, NULL, 0

-- Create a query to generate and populate a global temp table from above results
select 
@qry = 'Create table ##t(' +
stuff(  
    (select ',' + name + ' '+ system_type_name + ' NULL'
    from #d d For XML Path, TYPE)
    .value(N'.[1]', N'nvarchar(max)')
, 1,1,'')
+ ')

insert into ##t 
Exec '+@procname+' ' + @param

Exec sp_executesql @qry

-- Use below global temp table to query the data as you may
select * from ##t

-- **WARNING** Don't forget to drop the global temp table ##t.
--drop table ##t
drop table #d 

Розроблено та протестовано на версії сервера Sql - Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (збірка 17134 :)

Ви можете налаштувати схему для вашої версії SQL-сервера, яку ви використовуєте (за потреби).


4

Якщо ви знаєте параметри, які передаються, і якщо у вас немає доступу для створення sp_configure, відредагуйте збережену процедуру з цими параметрами, і те саме можна зберегти в глобальній таблиці ##.


3

Це можна зробити в SQL Server 2014+ за умови, що збережена процедура повертає лише одну таблицю. Якщо хтось знайде спосіб зробити це для кількох таблиць, я хотів би знати про це.

DECLARE @storedProcname NVARCHAR(MAX) = ''
SET @storedProcname = 'myStoredProc'

DECLARE @strSQL AS VARCHAR(MAX) = 'CREATE TABLE myTableName '

SELECT @strSQL = @strSQL+STUFF((
SELECT ',' +name+' ' + system_type_name 
FROM sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID(@storedProcname),0)
FOR XML PATH('')
),1,1,'(') + ')'

EXEC (@strSQL)

INSERT INTO myTableName

EXEC ('myStoredProc @param1=1, @param2=2')

SELECT * FROM myTableName

DROP TABLE myTableName

Це витягує визначення повернутої таблиці із системних таблиць і використовує це для створення таблиці темп для вас. Потім ви можете заповнити його із збереженої процедури, як зазначено раніше.

Існують також варіанти цього, які працюють і з Dynamic SQL.


2

На кілька років пізніше питання, але мені було потрібно щось подібне для швидкого та брудного генерування коду. Я вважаю, як інші заявили, що визначити тимчасову таблицю спереду просто простіше, але цей метод повинен працювати для простих запитів, що зберігаються, або статей sql.

Це буде дещо суперечливо, але воно запозичує тут учасників, а також рішення Пола Уайта від DBA Stack Exchange Отримати результати стовпців із результатами збереженої процедури. . Знову ж таки, повторити цей підхід та приклад не призначено для процесів у середовищі, що користуються декількома користувачами. У цьому випадку визначення таблиці встановлюється на короткий час у глобальній темп-таблиці для довідки за допомогою процесу генерації коду.

Я ще не повністю перевірив це, тому можуть бути застереження, тож ви, можливо, захочете перейти до посилання MSDN у відповіді Пола Уайта. Це стосується SQL 2012 та новіших версій.

Спочатку скористайтеся збереженою процедурою sp_describe_first_result_set, яка нагадує опис Oracle.

Це дасть оцінку першому рядку першого набору результатів, тому якщо ваша збережена процедура або оператор повертає кілька запитів, він опише лише перший результат.

Я створив збережену програму для розбиття завдань, що повертає одне поле для вибору для створення визначення таблиці темп.

CREATE OR ALTER PROCEDURE [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet]
(
     @sql NVARCHAR(4000)
    ,@table_name VARCHAR(100)
    ,@TableDefinition NVARCHAR(MAX) OUTPUT
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @TempTableDefinition NVARCHAR(MAX)
    DECLARE @NewLine NVARCHAR(4) = CHAR(13)+CHAR(10)

    DECLARE @ResultDefinition TABLE (  --The View Definition per MSDN
      is_hidden         bit NOT NULL
    , column_ordinal    int NOT NULL
    , [name]            sysname NULL
    , is_nullable       bit NOT NULL
    , system_type_id    int NOT NULL
    , system_type_name  nvarchar(256) NULL
    , max_length        smallint NOT NULL
    , [precision]       tinyint NOT NULL
    , scale             tinyint NOT NULL
    , collation_name    sysname NULL    
    , user_type_id      int NULL
    , user_type_database    sysname NULL    
    , user_type_schema  sysname NULL
    , user_type_name    sysname NULL    
    , assembly_qualified_type_name      nvarchar(4000)  
    , xml_collection_id         int NULL
    , xml_collection_database   sysname NULL    
    , xml_collection_schema     sysname NULL    
    , xml_collection_name       sysname NULL
    , is_xml_document           bit NOT NULL            
    , is_case_sensitive         bit NOT NULL            
    , is_fixed_length_clr_type  bit NOT NULL    
    , source_server             sysname NULL            
    , source_database           sysname NULL
    , source_schema             sysname NULL
    , source_table              sysname NULL
    , source_column             sysname NULL
    , is_identity_column        bit NULL
    , is_part_of_unique_key     bit NULL
    , is_updateable             bit NULL
    , is_computed_column        bit NULL
    , is_sparse_column_set      bit NULL
    , ordinal_in_order_by_list  smallint NULL   
    , order_by_is_descending    smallint NULL   
    , order_by_list_length      smallint NULL
    , tds_type_id               int NOT NULL
    , tds_length                int NOT NULL
    , tds_collation_id          int NULL
    , tds_collation_sort_id     tinyint NULL
    )

    --Insert the description into table variable    
    INSERT @ResultDefinition
    EXEC sp_describe_first_result_set @sql

    --Now Build the string to create the table via union select statement
    ;WITH STMT AS (
        SELECT N'CREATE TABLE ' + @table_name + N' (' AS TextVal
        UNION ALL

        SELECT 
         CONCAT(
                CASE column_ordinal
                    WHEN 1 THEN '     ' ELSE '   , ' END  --Determines if comma should precede
                , QUOTENAME([name]) , '   ', system_type_name  -- Column Name and SQL TYPE
                ,CASE is_nullable 
                    WHEN 0 THEN '   NOT NULL' ELSE '   NULL' END --NULLABLE CONSTRAINT          
               ) AS TextVal
        FROM @ResultDefinition WHERE is_hidden = 0  -- May not be needed
        UNION ALL

        SELECT N');' + @NewLine
    ) 

    --Now Combine the rows to a single String
    SELECT @TempTableDefinition = COALESCE (@TempTableDefinition + @NewLine + TextVal, TextVal) FROM STMT

    SELECT @TableDefinition = @TempTableDefinition
END

Загадка полягає в тому, що вам потрібно використовувати глобальну таблицю, але її потрібно зробити достатньо унікальною, щоб ви могли часто кидати і створювати з неї, не турбуючись про зіткнення.
У прикладі я використав посібник (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) для глобальної змінної, замінивши дефіси на підкреслення

DECLARE @sql NVARCHAR(4000) = N'SELECT @@SERVERNAME as ServerName, GETDATE() AS Today;'
DECLARE @GlobalTempTable VARCHAR(100) = N'##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable'

--@sql can be a stored procedure name like dbo.foo without parameters

DECLARE @TableDef NVARCHAR(MAX)

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

EXEC [dbo].[sp_GetTableDefinitionFromSqlBatch_DescribeFirstResultSet] 
    @sql, @GlobalTempTable, @TableDef OUTPUT

--Creates the global table ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
EXEC sp_executesql @TableDef 

--Now Call the stored procedure, SQL Statement with Params etc.
INSERT ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable
    EXEC sp_executesql @sql 

--Select the results into your undefined Temp Table from the Global Table
SELECT * 
INTO #MyTempTable
FROM ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

SELECT * FROM #MyTempTable

DROP TABLE IF EXISTS #MyTempTable
DROP TABLE IF EXISTS ##FE264BF5_9C32_438F_8462_8A5DC8DEE49E_MyTempTable

Знову ж таки, я перевірив це лише простими запитами, що зберігаються, і простими запитами, тому ваш пробіг може відрізнятися. Сподіваюся, що це комусь допоможе.


1

Ну, вам потрібно створити тимчасову таблицю, але вона не повинна мати правильну схему .... Я створив збережену процедуру, яка модифікує існуючу таблицю темп, щоб вона мала необхідні стовпці з потрібними даними тип та порядок (скидання всіх існуючих стовпців, додавання нових стовпців):

GO
create procedure #TempTableForSP(@tableId int, @procedureId int)  
as   
begin  
    declare @tableName varchar(max) =  (select name  
                                        from tempdb.sys.tables 
                                        where object_id = @tableId
                                        );    
    declare @tsql nvarchar(max);    
    declare @tempId nvarchar(max) = newid();      
    set @tsql = '    
    declare @drop nvarchar(max) = (select  ''alter table tempdb.dbo.' + @tableName 
            +  ' drop column ''  + quotename(c.name) + '';''+ char(10)  
                                   from tempdb.sys.columns c   
                                   where c.object_id =  ' + 
                                         cast(@tableId as varchar(max)) + '  
                                   for xml path('''')  
                                  )    
    alter table tempdb.dbo.' + @tableName + ' add ' + QUOTENAME(@tempId) + ' int;
    exec sp_executeSQL @drop;    
    declare @add nvarchar(max) = (    
                                select ''alter table ' + @tableName 
                                      + ' add '' + name 
                                      + '' '' + system_type_name 
                           + case when d.is_nullable=1 then '' null '' else '''' end 
                                      + char(10)   
                              from sys.dm_exec_describe_first_result_set_for_object(' 
                               + cast(@procedureId as varchar(max)) + ', 0) d  
                                order by column_ordinal  
                                for xml path(''''))    

    execute sp_executeSQL  @add;    
    alter table '  + @tableName + ' drop column ' + quotename(@tempId) + '  ';      
    execute sp_executeSQL @tsql;  
end         
GO

create table #exampleTable (pk int);

declare @tableId int = object_Id('tempdb..#exampleTable')
declare @procedureId int = object_id('examplestoredProcedure')

exec #TempTableForSP @tableId, @procedureId;

insert into #exampleTable
exec examplestoredProcedure

Зверніть увагу, це не спрацює, якщо sys.dm_exec_describe_first_result_set_for_object не зможе визначити результати збереженої процедури (наприклад, якщо вона використовує таблицю temp).


0

Якщо ви дозволите динамічному SQL створювати таблицю темпів, ця таблиця належить динамічному підключенню SQL, на відміну від з'єднання, з якого викликається збережена процедура.

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;

введіть тут опис зображення

DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

SELECT * FROM #Pivoted;

Повідомлення 208, Рівень 16, стан 0 Недійсне ім'я об'єкта '#Pivoted'. Це тому, що #Pivoted належить підключенню Dynamic SQL. Отже остання інструкція

SELECT * FROM #Pivoted

не вдається.

Один із способів не стикатися з цією проблемою - переконатися, що всі посилання на #Pivoted зроблені всередині самого динамічного запиту:

DECLARE @COMMA_SEPARATED_KEYS varchar(MAX);
DROP TABLE IF EXISTS KV;
CREATE TABLE KV (id_person int, mykey varchar(30), myvalue int);
INSERT INTO KV VALUES
(1, 'age', 16),
(1, 'weight', 63),
(1, 'height', 175),
(2, 'age', 26),
(2, 'weight', 83),
(2, 'height', 185);
WITH cte(mykey) AS (
    SELECT DISTINCT mykey FROM KV
) 
SELECT @COMMA_SEPARATED_KEYS=STRING_AGG(mykey,',') FROM cte;
SELECT @COMMA_SEPARATED_KEYS AS keys;


DECLARE @ExecuteExpression varchar(MAX);

DROP TABLE IF EXISTS #Pivoted;

SET @ExecuteExpression = N'
SELECT * 
INTO #Pivoted
FROM
(
    SELECT
        mykey,
        myvalue,
        id_person
    FROM KV
) AS t
PIVOT(
    MAX(t.myvalue) 
    FOR mykey IN (COMMA_SEPARATED_KEYS)
) AS pivot_table;
SELECT * FROM #Pivoted;
';

SET @ExecuteExpression = REPLACE(@ExecuteExpression, 'COMMA_SEPARATED_KEYS', @COMMA_SEPARATED_KEYS);

EXEC(@ExecuteExpression);

введіть тут опис зображення


-5

Я би зробив наступне

  1. Створіть (конвертуйте SP в) UDF (табличне значення UDF).

  2. select * into #tmpBusLine from dbo.UDF_getBusinessLineHistory '16 Mar 2009'


2
Можливо, буде якась перешкода, щоб зробити ваш перший крок. На прикладі, якщо в оригінальному SP використовуються тимчасові таблиці. UDF не можуть використовувати тимчасові таблиці.
лютого
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.