SQL Server - ВЫБРАТЬ ИЗ хранимой процедуры

334

У меня есть хранимая процедура, которая возвращает строки:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Моя настоящая процедура немного сложнее, поэтому необходим sproc.

Можно ли выбрать выход, вызвав эту процедуру?

Что-то вроде:

SELECT * FROM (EXEC MyProc) AS TEMP

Мне нужно использовать SELECT TOP X, ROW_NUMBERи дополнительный WHEREпункт на странице мои данные, и я не хочу , чтобы передать эти значения в качестве параметров.

jonathanpeppers
источник
Я не уверен, что вы собираетесь делать здесь, потому что когда вы выполняете процедуру, вы получаете строки обратно. Это то, что вы хотите выполнить процедуру внутри инструкции SELECT, чтобы вы могли связать ее с доступным для страниц объектом?
Радж Море
1
Есть ли конкретная причина, по которой вы не хотите передавать значения в качестве параметров? Делать так, как вы предлагаете, немного неэффективно - вы бы выбрали больше данных, чем вам нужно, а затем не использовали бы их все.
Марк Белл
2
Посмотрите здесь: sommarskog.se/share_data.html
pylover

Ответы:

149

Вы можете использовать пользовательскую функцию или представление вместо процедуры.

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

Мехрдад Афшари
источник
8
Кроме того, если после преобразования в UDF вам понадобится семантика хранимых процедур, вы всегда можете обернуть UDF процедурой.
Джоэл Кохорн
что если нам нужно отправить параметры нескольким хранимым процедурам и объединить их в одну большую хранимую процедуру? Может просматривать, принимать параметры, как хранимые процедуры
mrN
3
@mrN Представления не принимают параметры, но UDFs.
Мердад Афшари
3
Здравствуйте, мне действительно нужно сделать это без преобразования sp в представление или функцию, это возможно?
Луис Бесерриль
2
Хотя ваш ответ является верным утверждением, он не отвечает на вопрос ... "ВЫБРАТЬ ИЗ ХРАНЕНОЙ ПРОЦЕДУРЫ" Что, конечно, не идеально, но именно так ... @ Ответ Аамира - правильный ответ. Либо это, либо вопрос нужно изменить ... что немного смешно для меня.
Urasquirrel
202

Ты можешь

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

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...
Чарльз Бретана
источник
34
Проблема INSERT #Tили INSERT @Tв том , что INSERT EXECоператор не может быть вложенными. Если хранимая процедура уже содержит INSERT EXECв себе, это не будет работать.
MOHCTP
2
Это, вероятно, самое переносимое решение, наиболее близкое к базовому SQL. Это также помогает поддерживать строгие определения типов столбцов. Должен иметь больше голосов, чем выше.
В переменной таблице выглядит более полезной здесь , чем временные таблицы в терминах зра перекомпиляции. Так что я согласен, этот ответ должен иметь больше голосов.
Реснянский
76

Вам нужна либо функция с табличным значением, либо вставьте EXEC во временную таблицу:

INSERT INTO #tab EXEC MyProc
CMerat
источник
32
Проблема INSERT #Tили INSERT @Tв том , что INSERT EXECоператор не может быть вложенными. Если хранимая процедура уже содержит INSERT EXECв себе, это не будет работать.
MOHCTP
46

Вы должны прочитать об OPENROWSET и OPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
Ризван Мумтаз
источник
4
Как динамически получить YOURSERVERNAME? Вы не можете ожидать, чтобы знать всегда. Разве это не сломается каждый вторник? Так что, если у меня есть 100 серверов с разными именами ...
Urasquirrel
И что делать, если моя база данных не настроена на это?
Urasquirrel
4
Попробуйте @@ servername, чтобы получить его динамически
Сиддхартха Ганди
44

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

declare @MyTableType as table
(
FIRSTCOLUMN int
,.....
)  

Затем вам нужно вставить результат вашей хранимой процедуры в тип таблицы, который вы только что определили

Insert into @MyTableType 
EXEC [dbo].[MyStoredProcedure]

В конце просто выберите из вашего типа таблицы

Select * from @MyTableType
Аамир
источник
Это лучшее решение для меня, потому что вам не нужно указывать имя сервера, строки подключения или настраивать какие-либо связанные серверы, чтобы заставить его работать - это вещи, которые я не хочу делать, чтобы просто получить некоторые данные обратно. Спасибо! Внушительный ответ!
Мэтт
Хороший ответ ღ❤ ೋ ღ❤ღ ೋ❤ ღ
Нахид
Когда хранимая процедура слишком сложна - этот метод не работает, например, когда хранимая процедура использует две временные таблицы.
nick_n_a
34

Не обязательно использовать временную таблицу.

Это мое решение

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue
DavideDM
источник
2
Для этого вам нужно добавить свой сервер как связанный сервер к себе, но это работает как шарм! Спасибо!
Вахидс
Вот некоторые
Кейт Адлер
1
Хм ... Я получаю сообщение об ошибке "Ошибка 7411: сервер 'YourServerName' не настроен для доступа к данным." Что мне нужно изменить?
Мэтт
Вы добавили свой сервер как связанный сервер? YourServerName - это имя вашего сервера. Вы должны изменить YourServerName с вашим реальным именем сервера.
DavideDM
@Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
alexkovelsky
23

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

CREATE TABLE #GetVersionValues
(
    [Index] int,
    [Name]  sysname,
    Internal_value  int,
    Character_Value sysname
)
INSERT #GetVersionValues EXEC master.dbo.xp_msver 'WindowsVersion'
SELECT * FROM #GetVersionValues
drop TABLE #GetVersionValues

источник
7

используйте OPENQUERY и перед исполнением set 'SET FMTONLY OFF; ВКЛЮЧИТЕ NOCOUNT; '

Попробуйте этот пример кода:

SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE  [database].[dbo].[storedprocedure]  value,value ')
Али Асгар Фендерески
источник
6

Попробуйте преобразовать вашу процедуру во встроенную функцию, которая возвращает таблицу следующим образом:

CREATE FUNCTION MyProc()
RETURNS TABLE AS
RETURN (SELECT * FROM MyTable)

И тогда вы можете назвать это как

SELECT * FROM MyProc()

У вас также есть возможность передачи параметров в функцию следующим образом:

CREATE FUNCTION FuncName (@para1 para1_type, @para2 para2_type , ... ) 

И называть это

SELECT * FROM FuncName ( @para1 , @para2 )
al_the_man
источник
6

Если «Доступ к данным» ложь,

EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE

после,

SELECT  *  FROM OPENQUERY(SQLSERVERNAME, 'EXEC DBNAME..MyProc @parameters')

оно работает.

Али Осман Явуз
источник
5

Вы можете немного обмануть с OPENROWSET:

SELECT ...fieldlist...
FROM OPENROWSET('SQLNCLI', 'connection string', 'name of sp')
WHERE ...

Конечно, каждый раз запускается весь SP.

MartW
источник
4

Для простоты и возможности повторного запуска я использовал систему StoredProcedure sp_readerrorlog для получения данных:

-----USING Table Variable
DECLARE @tblVar TABLE (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(MAX),
   [Text] NVARCHAR(MAX)
)
INSERT INTO @tblVar Exec sp_readerrorlog
SELECT LogDate as DateOccured, ProcessInfo as pInfo, [Text] as Message FROM @tblVar



-----(OR): Using Temp Table
IF OBJECT_ID('tempdb..#temp') IS NOT NULL  DROP TABLE #temp;
CREATE TABLE #temp (
   LogDate DATETIME,
   ProcessInfo NVARCHAR(55),
   Text NVARCHAR(MAX)
)
INSERT INTO #temp EXEC sp_readerrorlog
SELECT * FROM #temp
Шейх каузер
источник
1

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

Лоуренс Барсанти
источник
1

Если ваш сервер называется SERVERX, например, я так и сделал ...

EXEC sp_serveroption 'SERVERX', 'DATA ACCESS', TRUE;
DECLARE @CMD VARCHAR(1000);
DECLARE @StudentID CHAR(10);
SET @StudentID = 'STUDENT01';
SET @CMD = 'SELECT * FROM OPENQUERY([SERVERX], ''SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE MYDATABASE.dbo.MYSTOREDPROC ' + @StudentID + ''') WHERE SOMEFIELD = SOMEVALUE';
EXEC (@CMD);

Чтобы убедиться, что это работает, я закомментировал EXEC()командную строку и заменил ее SELECT @CMDна просмотр команды перед тем, как пытаться ее выполнить! Это должно было гарантировать, что все правильное количество одинарных кавычек было в правильном месте. :-)

Я надеюсь, что это помогает кому-то.

Fandango68
источник