Máy chủ SQL - CHỌN TỪ thủ tục lưu trữ


333

Tôi có một thủ tục được lưu trữ trả về các hàng:

CREATE PROCEDURE MyProc
AS
BEGIN
    SELECT * FROM MyTable
END

Thủ tục thực tế của tôi phức tạp hơn một chút, đó là lý do tại sao một sproc là cần thiết.

Có thể chọn đầu ra bằng cách gọi thủ tục này?

Cái gì đó như:

SELECT * FROM (EXEC MyProc) AS TEMP

Tôi cần phải sử dụng SELECT TOP X, ROW_NUMBERvà thêm WHEREkhoản để trang dữ liệu của tôi, và tôi không thực sự muốn vượt qua những giá trị như thông số.


Tôi không chắc chắn về những gì bạn định làm ở đây bởi vì khi bạn thực hiện thủ tục, bạn sẽ nhận được các hàng trở lại. Có phải là bạn muốn thực hiện thủ tục bên trong một câu lệnh CHỌN để bạn có thể buộc nó vào một đối tượng có thể phân trang?
Raj Thêm

1
Có một lý do cụ thể tại sao bạn không muốn truyền các giá trị làm tham số không? Để làm điều đó theo cách bạn đang đề xuất là một chút không hiệu quả - bạn sẽ chọn nhiều dữ liệu hơn bạn cần, và sau đó không sử dụng tất cả.
Đánh dấu

2
Hãy xem tại đây: sommarskog.se/share_data.html
pylover

Câu trả lời:


149

Bạn có thể sử dụng chức năng do Người dùng xác định hoặc chế độ xem thay vì quy trình.

Một thủ tục có thể trả về nhiều tập kết quả, mỗi bộ có lược đồ riêng. Nó không phù hợp để sử dụng trong một SELECTtuyên bố.


8
Ngoài ra, nếu sau khi chuyển đổi sang UDF, bạn thấy bạn cần ngữ nghĩa thủ tục được lưu trữ, bạn luôn có thể bọc UDF bằng một thủ tục.
Joel Coehoorn

Điều gì xảy ra nếu, chúng ta cần gửi các tham số cho các thủ tục được lưu trữ và kết hợp chúng thành một thủ tục được lưu trữ lớn? Có thể xem, lấy tham số, giống như các thủ tục được lưu trữ
mrN

3
@mrN Lượt xem không lấy tham số, nhưng UDF thì có.
Mehrdad Afshari

3
Xin chào, tôi thực sự cần phải làm điều này mà không cần chuyển đổi sp thành chế độ xem hoặc chức năng, liệu có thể?
Luis Becerril

2
Mặc dù câu trả lời của bạn là một tuyên bố đúng nhưng nó không trả lời câu hỏi .... "CHỌN TỪ thủ tục được lưu trữ" Điều đó chắc chắn không lý tưởng, nhưng đó là câu trả lời ... @ Aamir là câu trả lời đúng. Hoặc là hoặc câu hỏi cần phải được thay đổi ... có vẻ hơi vô lý với tôi.
Urasquirrel

201

Bạn có thể

  1. tạo một biến bảng để giữ tập kết quả từ Proc được lưu trữ và sau đó
  2. chèn đầu ra của Proc được lưu trữ vào biến bảng, và sau đó
  3. sử dụng biến bảng chính xác như bất kỳ bảng nào khác ...

... sql ....

Declare @T Table ([column definitions here])
Insert @T Exec storedProcname params 
Select * from @T Where ...

34
Vấn đề với INSERT #Thoặc INSERT @Tlà một INSERT EXECtuyên bố không thể được lồng nhau. Nếu thủ tục được lưu trữ đã có INSERT EXECtrong đó, thì thủ tục này sẽ không hoạt động.
MOHCTP

2
Đây có lẽ là giải pháp di động nhất, gần nhất với SQL cơ bản. Nó cũng giúp duy trì các định nghĩa loại cột mạnh. Nên có nhiều upvote hơn những người ở trên.

Các biến bảng có vẻ hữu ích hơn ở đây so với các bảng tạm thời về mặt biên dịch lại sp. Vì vậy, tôi đồng ý, câu trả lời này nên có nhiều upvote.
resnyanskiy

76

Bạn có muốn một chức năng Giá trị Bảng hoặc chèn EXEC của bạn vào một bảng tạm thời:

INSERT INTO #tab EXEC MyProc

31
Vấn đề với INSERT #Thoặc INSERT @Tlà một INSERT EXECtuyên bố không thể được lồng nhau. Nếu thủ tục được lưu trữ đã có INSERT EXECtrong đó, thì thủ tục này sẽ không hoạt động.
MOHCTP

46

Bạn phải đọc về OPENWAYSETOPENQUERY

SELECT  * 
INTO    #tmp FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')

4
Làm thế nào để có được năng động của bạn? Bạn không thể mong đợi phải luôn luôn biết. Điều này sẽ không phá vỡ mỗi thứ ba khác? Vì vậy, nếu tôi có tất cả 100 máy chủ với các tên khác nhau ...
Urasquirrel

còn nếu cơ sở dữ liệu của tôi không được cấu hình để cho phép điều này thì sao?
Urasquirrel

4
Hãy thử @@ servername để có được nó một cách linh hoạt
Siddhartha Gandhi

44

Bạn cần khai báo một loại bảng chứa cùng số cột mà quy trình lưu trữ của bạn đang trả về. Các kiểu dữ liệu của các cột trong loại bảng và các cột được trả về bởi các thủ tục phải giống nhau

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

Sau đó, bạn cần chèn kết quả của thủ tục được lưu trữ vào loại bảng bạn vừa xác định

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

Cuối cùng, chỉ cần chọn từ loại bảng của bạn

Select * from @MyTableType

Đó là giải pháp tốt nhất cho tôi, vì bạn không cần chỉ định tên máy chủ, chuỗi kết nối hoặc phải định cấu hình bất kỳ máy chủ được liên kết nào để làm cho nó hoạt động - đó là những điều tôi không muốn làm chỉ để có được một số dữ liệu trở lại. Cảm ơn bạn! Câu trả lời tuyệt vời!
Matt

Câu trả lời hay ೋ ღ❤ღ ೋ❤
Nahid

Khi thủ tục được lưu trữ quá khó khăn - phương pháp này không hoạt động, ví dụ, khi thủ tục được lưu trữ sử dụng hai bảng tạm thời.
nickầua

34

Không cần thiết sử dụng một bảng tạm thời.

Đây là giải pháp của tôi

SELECT  *  FROM    
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc @parameters')
WHERE somefield = anyvalue

2
Điều này cần bạn thêm máy chủ của bạn như một máy chủ được liên kết với chính nó, nhưng nó hoạt động như một cơ duyên! cảm ơn!
vaheed

Một số cảnh báo tuyệt vời về điều này: stackoverflow.com/questions/2374741/ trộm
Keith Adler

1
Hmm ... Tôi đang gặp lỗi "Lỗi 7411: Máy chủ 'YourServerName' không được định cấu hình cho DATA ACCESS." Tôi cần gì để thay đổi?
Matt

Bạn đã thêm máy chủ của bạn như một máy chủ được liên kết? YourServerName là tên của máy chủ của bạn. Bạn phải thay đổi YourServerName bằng tên máy chủ thực của bạn.
DavideDM

@Matt:sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;
alexkovelsky

23

Bạn có thể sao chép đầu ra từ bảng sp sang bảng tạm thời.

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

sử dụng OPENQUERY và trước khi thực hiện cài đặt 'SET FMTONLY OFF; THIẾT LẬP NOCOUNT; '

Hãy thử mã mẫu này:

SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE  [database].[dbo].[storedprocedure]  value,value ')

6

Hãy thử chuyển đổi thủ tục của bạn thành Hàm nội tuyến trả về bảng như sau:

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

Và sau đó bạn có thể gọi nó là

SELECT * FROM MyProc()

Bạn cũng có tùy chọn truyền tham số cho hàm như sau:

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

Và gọi nó

SELECT * FROM FuncName ( @para1 , @para2 )

6

Nếu 'TRUY CẬP DỮ LIỆU' sai,

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

sau,

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

nó hoạt động


5

Bạn có thể gian lận một chút với MỞ ĐẦU:

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

Điều này vẫn sẽ chạy toàn bộ SP mỗi lần, tất nhiên.


4

Để đơn giản và để có thể chạy lại, tôi đã sử dụng hệ thống StoredProcedure "sp_readerrorlog" để lấy dữ liệu:

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

Có vẻ như bạn chỉ cần sử dụng một khung nhìn . Một khung nhìn cho phép một truy vấn được biểu diễn dưới dạng bảng để nó, khung nhìn, có thể được truy vấn.


1

Nếu máy chủ của bạn được gọi là SERVERX chẳng hạn, thì đây là cách tôi đã làm ...

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

Để kiểm tra điều này có hiệu quả, tôi đã nhận xét EXEC()dòng lệnh và thay thế nó SELECT @CMDđể xem lại lệnh trước khi thử thực thi nó! Đó là đảm bảo tất cả số lượng trích dẫn chính xác được đặt đúng chỗ. :-)

Tôi hy vọng điều đó sẽ giúp được ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.