Выберите столбцы из набора результатов хранимой процедуры - PullRequest
416 голосов
/ 16 октября 2008

У меня есть хранимая процедура, которая возвращает 80 столбцов и 300 строк. Я хочу написать выбор, который получает 2 из этих столбцов. Что-то вроде

SELECT col1, col2 FROM EXEC MyStoredProc 'param1', 'param2'

Когда я использовал вышеуказанный синтаксис, я получаю ошибку:

«Неверное имя столбца».

Я знаю, что самым простым решением было бы изменить хранимую процедуру, но я ее не написал и не могу ее изменить.

Есть ли способ сделать то, что я хочу?

  • Я мог бы создать временную таблицу для размещения результатов, но, поскольку в ней 80 столбцов, мне нужно было бы создать временную таблицу из 80 столбцов, чтобы получить 2 столбца. Я хотел избежать отслеживания всех возвращаемых столбцов.

  • Я пытался использовать WITH SprocResults AS ...., как предложил Марк, но я получил 2 ошибки

    Неверный синтаксис рядом с ключевым словом 'EXEC'.
    Неверный синтаксис рядом с ')'.

  • Я попытался объявить табличную переменную, и я получил следующую ошибку

    Ошибка вставки: имя столбца или количество предоставленных значений не соответствует определению таблицы

  • Если я попытаюсь
    SELECT * FROM EXEC MyStoredProc 'param1', 'param2'
    Я получаю ошибку:

    Неверный синтаксис рядом с ключевым словом "exec".

Ответы [ 16 ]

174 голосов
/ 16 октября 2008

Можете ли вы разделить запрос? Вставьте сохраненные результаты процедуры в табличную переменную или временную таблицу. Затем выберите 2 столбца из табличной переменной.

Declare @tablevar table(col1 col1Type,..
insert into @tablevar(col1,..) exec MyStoredProc 'param1', 'param2'

SELECT col1, col2 FROM @tablevar
81 голосов
/ 16 октября 2008

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

Как обмениваться данными между хранимыми процедурами

Ответ Гульзара будет работать (он задокументирован в приведенной выше ссылке), но писать его будет непросто (вам нужно будет указать все 80 имен столбцов в вашем выражении @tablevar (col1, ...). в будущем, если в схему будет добавлен столбец или изменен вывод, его нужно будет обновить в коде, иначе произойдет ошибка.

77 голосов
/ 19 октября 2010
CREATE TABLE #Result
(
  ID int,  Name varchar(500), Revenue money
)
INSERT #Result EXEC RevenueByAdvertiser '1/1/10', '2/1/10'
SELECT * FROM #Result ORDER BY Name
DROP TABLE #Result

Источник:
http://stevesmithblog.com/blog/select-from-a-stored-procedure/

38 голосов
/ 04 февраля 2011

Это работает для меня: (т.е. мне нужно только 2 столбца из 30+, возвращаемых sp_help_job)

SELECT name, current_execution_status 
FROM OPENQUERY (MYSERVER, 
  'EXEC msdb.dbo.sp_help_job @job_name = ''My Job'', @job_aspect = ''JOB''');  

Прежде чем это сработает, мне нужно было запустить:

sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;

.... чтобы обновить таблицу sys.servers. (т.е. использование собственной ссылки в OPENQUERY по умолчанию отключено.)

По моему простому требованию я не столкнулся ни с одной из проблем, описанных в разделе OPENQUERY превосходной ссылки Ланса.

Россини, если вам нужно динамически установить эти входные параметры, тогда использование OPENQUERY становится немного более неудобным:

DECLARE @innerSql varchar(1000);
DECLARE @outerSql varchar(1000);

-- Set up the original stored proc definition.
SET @innerSql = 
'EXEC msdb.dbo.sp_help_job @job_name = '''+@param1+''', @job_aspect = N'''+@param2+'''' ;

-- Handle quotes.
SET @innerSql = REPLACE(@innerSql, '''', '''''');

-- Set up the OPENQUERY definition.
SET @outerSql = 
'SELECT name, current_execution_status 
FROM OPENQUERY (MYSERVER, ''' + @innerSql + ''');';

-- Execute.
EXEC (@outerSql);

Я не уверен в различиях (если есть) между использованием sp_serveroption для непосредственного обновления существующей самореференции sys.servers и использованием sp_addlinkedserver (как описано в ссылке Ланса) для создания дубликата / псевдоним.

Примечание 1: Я предпочитаю OPENQUERY, а не OPENROWSET, учитывая, что OPENQUERY не требует определения строки соединения внутри proc.

Примечание 2: Сказав все это: обычно я бы просто использовал INSERT ... EXEC :) Да, это 10 минут дополнительного набора текста, но если я могу помочь, я предпочитаю не шутить с:
(а) кавычки в кавычках в кавычках и
(б) sys-таблицы и / или хитрые самосвязанные настройки связанных серверов (т. е. для этого мне нужно доверить свое дело нашим всемогущим администраторам баз данных :)

Однако в этом случае я не смог использовать конструкцию INSERT ... EXEC, так как sp_help_job уже использует ее. («Оператор INSERT EXEC не может быть вложенным.»)

10 голосов
/ 24 июня 2010

Может быть полезно знать, почему это так сложно. Хранимая процедура может только возвращать текст (печатать «текст»), или может возвращать несколько таблиц, или может вообще не возвращать таблицы.

Так что-то вроде SELECT * FROM (exec sp_tables) Table1 не будет работать

9 голосов
/ 31 января 2015

Если вы можете изменить хранимую процедуру, вы можете легко поместить необходимые определения столбцов в качестве параметра и использовать автоматически созданную временную таблицу:

CREATE PROCEDURE sp_GetDiffDataExample
      @columnsStatement NVARCHAR(MAX) -- required columns statement (e.g. "field1, field2")
AS
BEGIN
    DECLARE @query NVARCHAR(MAX)
    SET @query = N'SELECT ' + @columnsStatement + N' INTO ##TempTable FROM dbo.TestTable'
    EXEC sp_executeSql @query
    SELECT * FROM ##TempTable
    DROP TABLE ##TempTable
END

В этом случае вам не нужно создавать временную таблицу вручную - она ​​создается автоматически. Надеюсь, это поможет.

9 голосов
/ 03 сентября 2014

Для этого сначала создайте #test_table, как показано ниже:

create table #test_table(
    col1 int,
    col2 int,
   .
   .
   .
    col80 int
)

Теперь выполните процедуру и введите значение в #test_table:

insert into #test_table
EXEC MyStoredProc 'param1', 'param2'

Теперь вы получаете значение из #test_table:

select col1,col2....,col80 from #test_table
8 голосов
/ 16 октября 2008

(при условии, что SQL Server)

Единственный способ работать с результатами хранимой процедуры в T-SQL - это использовать синтаксис INSERT INTO ... EXEC. Это дает вам возможность вставлять во временную таблицу или переменную таблицы и оттуда выбирать нужные данные.

7 голосов
/ 09 ноября 2012

Если вы делаете это для ручной проверки данных, вы можете сделать это с помощью LINQPad.

Создайте соединение с базой данных в LinqPad, затем создайте операторы C #, подобные следующим:

DataTable table = MyStoredProc (param1, param2).Tables[0];
(from row in table.AsEnumerable()
 select new
 {
  Col1 = row.Field<string>("col1"),
  Col2 = row.Field<string>("col2"),
 }).Dump();

Ссылка http://www.global -webnet.net / blogengine / post / 2008/09/10 / LINQPAD-Использование-хранимых процедур-Доступ-Data -et.et.pp

7 голосов
/ 28 января 2012

Быстрый взлом состоит в добавлении нового параметра '@Column_Name' и вызове функции, определяющей имя столбца для извлечения. В возвращаемой части вашего sproc вы должны иметь операторы if / else и возвращать только указанный столбец, или, если он пуст - возвращать все.

CREATE PROCEDURE [dbo].[MySproc]
        @Column_Name AS VARCHAR(50)
AS
BEGIN
    IF (@Column_Name = 'ColumnName1')
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1'
        END
    ELSE
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1', @ColumnItem2 as 'ColumnName2', @ColumnItem3 as 'ColumnName3'
        END
END
...