Chèn kết quả của một thủ tục được lưu trữ vào một bảng tạm thời


1579

Làm thế nào để tôi làm một SELECT * INTO [temp table] FROM [stored procedure]? Không FROM [Table]và không xác định [temp table]?

Selecttất cả dữ liệu từ BusinessLinethành tmpBusLinecông trình tốt.

select *
into tmpBusLine
from BusinessLine

Tôi đang cố gắng như vậy, nhưng sử dụng stored proceduredữ liệu trả về dữ liệu, không hoàn toàn giống nhau.

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

Thông báo đầu ra:

Msg 156, Cấp 15, Trạng thái 1, Dòng 2 Cú pháp không chính xác gần từ khóa 'exec'.

Tôi đã đọc một số ví dụ về việc tạo một bảng tạm thời có cùng cấu trúc với thủ tục được lưu trữ đầu ra, hoạt động tốt, nhưng sẽ không tốt nếu không cung cấp bất kỳ cột nào.


22
Với CHỌN * VÀO [TABLE TÊN], bạn biết các cột, vì chúng được sao chép từ bảng gốc. Đây chính xác là những gì tôi muốn nếu tôi làm điều tương tự với một thủ tục được lưu trữ.
Ferdeen 17/03/2016


7
Chỉ muốn chỉ ra rằng "select * vào tmpBusLine" tạo ra một bảng vĩnh viễn. Bạn có thể muốn "chọn * vào #tmpBusLine". Tôi chắc chắn người đăng ban đầu đã phát hiện ra điều này nhưng nó có thể giúp những người khác tìm thấy bài đăng này vì đây là kết quả hàng đầu hiện tại cho tìm kiếm "chọn vào bảng tạm thời"
ktam33

2
Tôi không biết điều này có được giải quyết hay không nhưng lý do tại sao bạn gặp lỗi là do từ khóa.
Wes Palmer

9
Microsoft cần thêm CHỌN * VÀO TỪ EXEC! Xin vui lòng!
kjmerf

Câu trả lời:


704

Bạn có thể sử dụng OPENWAYSET cho việc này. Có một cái nhìn. Tôi cũng đã bao gồm mã sp_cool để kích hoạt Truy vấn phân phối Ad Hoc, trong trường hợp nó chưa được bật.

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
Đây là cách đúng đắn để làm điều đó. OPENWAYSET là cách duy nhất để coi kết quả của một thủ tục được lưu trữ dưới dạng biểu thức bảng.
Rob Farley

37
Điều này có vẻ hơi cồng kềnh chỉ để chèn vào một bảng. Rất nhiều cấu hình để làm. Ngoài ra, khi tôi dùng thử, tôi nhận được "Msg 7357, Cấp 16, Trạng thái 2, Dòng 1 Không thể xử lý đối tượng" EXEC GetPartyAnalysisData 146 ". Nhà cung cấp OLE DB" SQLNCLI "cho máy chủ được liên kết" (null) "cho biết rằng đối tượng có không có cột hoặc người dùng hiện tại không có quyền trên đối tượng đó. " Vì vậy, bạn cần thiết lập một máy chủ được liên kết ...
Ferdeen

10
Bạn không cần một máy chủ được liên kết, nhưng bạn sẽ cần phải có chuỗi kết nối đúng ... và đồng thời, chỉ định đường dẫn đầy đủ đến quy trình được lưu trữ bao gồm tên cơ sở dữ liệu và chủ sở hữu của sp.
MartW

18
eeeee một tham chiếu đến cùng một máy chủ? bẩn thỉu. chắc chắn là có nhiều hack hơn là phải tự tạo bảng tạm thời
Tim Abell

23
Tôi đồng ý rằng đây là một hack và có lẽ nên tránh trừ khi lưng bạn dựa vào tường. Thay đổi sp thành một chức năng có lẽ là một góc tốt hơn để thực hiện. IMHO.
greg

624

Nếu bạn muốn làm điều đó mà không cần khai báo bảng tạm thời trước tiên, bạn có thể thử tạo một hàm do người dùng xác định thay vì một thủ tục được lưu trữ và làm cho hàm do người dùng xác định đó trả về một bảng. Thay vào đó, nếu bạn muốn sử dụng thủ tục được lưu trữ, hãy thử một cái gì đó như thế này:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

171
Tôi nghĩ vấn đề là tạo ra lược đồ mà không cần phải khai báo rõ ràng.
Craig

5
Tôi rất muốn biết sự khác biệt giữa giải pháp này và giải pháp của @Aaron Alton ở trên. Điều này có vẻ đơn giản hơn nhiều, nhưng tôi không chắc chắn về bất kỳ ý nghĩa khác.
funkymushroom

11
Điều này sẽ hoạt động nhưng nếu bạn thêm các cột bổ sung vào thủ tục được lưu trữ SpGetRecords, điều này sẽ nổ tung.
Brady Holt

15
Bạn chỉ nhận được một CHERTN VÀO EXEC cho mỗi ngăn xếp cuộc gọi. SpGetRecords và bất kỳ Proc nào khác mà nó gọi không được sử dụng chiến lược này trong mã riêng của họ. Điều này có thể gây bất ngờ cho những người duy trì SpGetRecords.
Matt Stephenson

33
Điều này hoàn toàn không trả lời câu hỏi và tôi không hiểu tại sao nó lại được nâng cao như vậy? OP đã tuyên bố rõ ràng "không xác định [bảng tạm thời]" và dòng đầu tiên của bạn có câu lệnh tạo bảng tạm thời.
NickG

296

Trong SQL Server 2005, bạn có thể sử dụng INSERT INTO ... EXECđể chèn kết quả của một thủ tục được lưu trữ vào một bảng. Từ tài liệu của MSDNINSERT (thực tế cho SQL Server 2000):

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

122
Điều này đòi hỏi các tác giả phải được xác định trước. Tôi đang cố gắng tránh điều này. Cảm ơn.
Ferdeen 17/03/2016

5
Tôi nghĩ rằng càng nhiều. Rất hữu ích Chèn vào các bảng tmp một cách nhanh chóng, nhưng không hữu ích nếu bạn cần biết cấu trúc dữ liệu được trả về từ một Proc được lưu trữ. Cảm ơn sự giúp đỡ của bạn.
Ferdeen 17/03/2016

3
Có một bài viết hay ở đây msdn.microsoft.com/en-us/l Library / aa175921.aspx
Rich Andrew

4
Để sử dụng cùng một lược đồ, bạn có thể tạo một bản sao như sau: chọn top 0 * vào tempTable từ realTable ( stackoverflow.com/a/9206463/73794 )
Ngay cả Miên

@EvenMien Tôi thoáng chốc phấn khích khi thấy bình luận của bạn ... nhưng thật đáng buồn là nó chỉ hoạt động nếu kết quả của bạn thực sự phản chiếu một bảng thực sự :(
BVernon

193

Đây là một câu trả lời cho một phiên bản sửa đổi một chút của câu hỏi của bạn. Nếu bạn có thể từ bỏ việc sử dụng một thủ tục được lưu trữ cho một hàm do người dùng định nghĩa, bạn có thể sử dụng một hàm do người dùng định nghĩa trong bảng nội tuyến. Đây thực chất là một thủ tục được lưu trữ (sẽ lấy tham số) trả về một bảng dưới dạng tập kết quả; và do đó sẽ đặt độc đáo với một tuyên bố INTO.

Đây là một bài viết nhanh về nó và các chức năng do người dùng xác định. Nếu bạn vẫn có nhu cầu lái xe cho một thủ tục được lưu trữ, bạn có thể bọc hàm nội tuyến do người dùng định nghĩa có giá trị bằng một thủ tục được lưu trữ. Quy trình được lưu trữ chỉ chuyển các tham số khi nó gọi select * từ hàm do người dùng định nghĩa trong bảng nội tuyến.

Vì vậy, ví dụ, bạn có một hàm do người dùng định nghĩa trong bảng nội tuyến để có danh sách khách hàng cho một khu vực cụ thể:

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

Sau đó, bạn có thể gọi hàm này để nhận kết quả như thế nào:

SELECT * FROM CustomersbyRegion(1)

Hoặc để thực hiện CHỌN VÀO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Nếu bạn vẫn cần một thủ tục được lưu trữ, sau đó bọc chức năng như sau:

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

Tôi nghĩ rằng đây là phương pháp 'hack-less' nhất để có được kết quả mong muốn. Nó sử dụng các tính năng hiện có như dự định sẽ được sử dụng mà không có biến chứng bổ sung. Bằng cách lồng hàm chức năng do người dùng định nghĩa bảng nội tuyến trong thủ tục được lưu trữ, bạn có quyền truy cập vào chức năng theo hai cách. Thêm! Bạn chỉ có một điểm bảo trì cho mã SQL thực tế.

Việc sử dụng OPENWAYSET đã được đề xuất, nhưng đây không phải là chức năng OPENWAYSET được sử dụng cho (Từ Sách trực tuyến):

Bao gồm tất cả thông tin kết nối được yêu cầu để truy cập dữ liệu từ xa từ nguồn dữ liệu OLE DB. Phương pháp này thay thế cho việc truy cập các bảng trong máy chủ được liên kết và là phương pháp kết nối và truy cập dữ liệu từ xa một lần bằng cách sử dụng OLE DB. Để tham khảo thường xuyên hơn đến các nguồn dữ liệu OLE DB, thay vào đó, hãy sử dụng các máy chủ được liên kết.

Sử dụng OPENWAYSET sẽ hoàn thành công việc, nhưng nó sẽ phải chịu một số chi phí bổ sung để mở các kết nối cục bộ và sắp xếp dữ liệu. Nó cũng có thể không phải là một lựa chọn trong mọi trường hợp vì nó yêu cầu quyền truy vấn đặc biệt gây ra rủi ro bảo mật và do đó có thể không được mong muốn. Ngoài ra, cách tiếp cận OPENWAYSET sẽ ngăn cản việc sử dụng các thủ tục được lưu trữ trả về nhiều hơn một tập kết quả. Việc gói nhiều hàm giá trị bảng do người dùng định nghĩa trong một thủ tục được lưu trữ có thể đạt được điều này.


4
+1 Hàm có giá trị bảng là một giải pháp thích hợp. Chúng ta nên lưu ý những nhược điểm nhỏ: hàm có giá trị bảng là một đối tượng cơ sở dữ liệu bổ sung và có thể cần phải cấp các đặc quyền cho nó.
spencer7593

2
Yêu giải pháp. Một nhược điểm nhỏ mà tôi gặp phải, đó là bảng của tôi không thể có thứ tự bằng cách nó có thể có nó trong thủ tục được lưu trữ. Chà, tôi sẽ sắp xếp nó ra
mrwaim

5
Thêm một nhược điểm - "Không thể truy cập các bảng tạm thời từ bên trong một chức năng"
mrwaim

7
Câu hỏi ban đầu là làm thế nào để chúng ta tạo một bảng tạm thời với kết quả của sp. Đây là một mô hình tốt, nhưng không giải quyết được câu hỏi này
greg

16
greg, dòng đầu tiên trong câu trả lời của tôi nói "Đây là câu trả lời cho một phiên bản sửa đổi một chút của câu hỏi của bạn." Nhận xét của bạn là dư thừa.
Christian Loris

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

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

2
Nhận một "Msg 208, Cấp 16, Trạng thái 1, Dòng 1 Tên đối tượng không hợp lệ 'tmpBusLine' (có thể vì nó không được xác định trước).
Ferdeen 17/03/2016

1
@Ferds: xin lỗi, lúc đầu không hiểu yêu cầu của bạn. Cập nhật với một giải pháp khác.
Quassnoi

26
Giải pháp tuyệt vời. Một cảnh báo, bạn sẽ cần bật 'TRUY CẬP DỮ LIỆU' trên máy chủ của mình: EXEC sp_serveroption 'TheServerName', 'DATA ACCESS', TRUE
jcollum

8
Bạn cũng sẽ cần cho phép truy cập từ xa vào máy chủ. Điều này sẽ có sự phân nhánh bảo mật.
BraveNewMath

7
Điều này sẽ không hoạt động nếu quy trình được lưu trữ đích sử dụng các bảng tạm thời
Sal

125

Giải pháp dễ nhất:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Nếu bạn không biết lược đồ thì bạn có thể làm như sau. Xin lưu ý rằng có những rủi ro bảo mật nghiêm trọng trong phương pháp này.

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

nếu tôi không biết cột kết quả trả về thì sao ??? tôi có nghĩa là cột có thể thay đổi. Vậy làm thế nào để chèn kết quả vào bảng tạm thời ???
CHIA SẺ SHEKHAR

Bạn có thể sử dụng OPENQUERY nhưng không được khuyến khích vì nó đi kèm với các lỗi bảo mật.
Tigerjz32

1
"nếu tôi không biết cột kết quả trả về thì" bạn không thể sử dụng nó trong logic của mình. Bạn sẽ sử dụng dữ liệu như thế nào nếu bạn không biết nó là gì?
Adriaan Davel

@AdriaanDavel Tôi đồng ý với bạn rằng bạn phải luôn biết dữ liệu của mình (cách thực hành tốt nhất), tuy nhiên điều anh ấy có thể nói là có những lúc sproc trả về các cột động và bạn không luôn biết lược đồ sẽ trông như thế nào. Trong trường hợp đó, bạn có thể sử dụng OPENWAYSET để chèn và tạo bảng khi đang di chuyển. Tuy nhiên, có những rủi ro bảo mật rõ ràng khi làm điều này ...
Tigerjz32

1
@nurettin đôi khi bạn không biết thủ tục lưu trữ sẽ trả về cái gì. Điều gì xảy ra trong trường hợp đó? Làm thế nào bạn có thể tạo một bảng tạm thời (khi bạn không biết thủ tục được lưu trữ sẽ trả về cái gì) và chèn vào nó từ một thủ tục được lưu trữ?
Tigerjz32

106

Khi thủ tục được lưu trữ trả về nhiều cột và bạn không muốn "tạo" thủ công một bảng tạm thời để giữ kết quả, tôi đã tìm thấy cách dễ nhất là đi vào thủ tục được lưu trữ và thêm mệnh đề "vào" trên câu lệnh chọn cuối cùng và thêm 1 = 0 vào mệnh đề where.

Chạy thủ tục được lưu trữ một lần và quay lại và xóa mã SQL bạn vừa thêm. Bây giờ, bạn sẽ có một bảng trống khớp với kết quả của thủ tục được lưu trữ. Bạn có thể "bảng kịch bản như tạo" cho một bảng tạm thời hoặc chỉ cần chèn trực tiếp vào bảng đó.


9
+1, đề xuất tuyệt vời. Bạn thậm chí có thể thêm một biến tùy chọn nhanh vào sproc có tên @TableCreate hoặc một cái gì đó tương tự mà khi không null thực hiện các bước trên. Không yêu cầu thay đổi sproc sau khi nó được thiết lập.
Ian Roke

1
@dotjoe Bạn có làm một SELECT INTObảng tạm thời và làm một bảng kịch bản như được tạo từ bảng tạm thời không? Bảng tạm thời xuất hiện tempdbnhưng tôi không thể nhấp chuột phải và tạo tập lệnh. Bất kỳ trợ giúp được đánh giá cao.
DotnetDude

2
@DotNetDude bạn có thể select ... into new_tablehoàn toàn tạo một bảng thực tế.
dotjoe

Sau đó lấy định nghĩa cột thô từ lược đồ bảng trống; thay thế '...' ở cuối bằng TABLE_NAME hợp pháp: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

Đây là giải pháp tốt nhất!
Lucas925

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
không giải quyết câu hỏi ban đầu của OP, thực hiện thao tác chèn mà không xác định bảng tạm thời trước.
t.durden

48

Có phải thủ tục lưu trữ của bạn chỉ lấy dữ liệu hoặc sửa đổi nó? Nếu nó chỉ được sử dụng để truy xuất, bạn có thể chuyển đổi thủ tục được lưu trữ thành hàm và sử dụng Biểu thức bảng chung (CTE) mà không phải khai báo, như sau:

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

Tuy nhiên, bất cứ điều gì cần được lấy từ CTE chỉ nên được sử dụng trong một câu lệnh. Bạn không thể làm một with temp as ...và cố gắng sử dụng nó sau một vài dòng SQL. Bạn có thể có nhiều CTE trong một câu lệnh cho các truy vấn phức tạp hơn.

Ví dụ,

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
Đây không phải là bảng tạm thời, là CTE. technet.microsoft.com/en-us/l
Library / từ

5
Cảm ơn @yucer ... Tôi tin rằng tôi đã không biết rằng họ đã được gọi là CTE sau đó :)
Người dùng SO

48

Nếu bảng kết quả của Proc được lưu trữ của bạn quá phức tạp để nhập câu lệnh "tạo bảng" bằng tay và bạn không thể sử dụng OPENQUERY HOẶC OPENWAYSET, bạn có thể sử dụng sp_help để tạo danh sách các cột và loại dữ liệu cho bạn. Khi bạn có danh sách các cột, vấn đề chỉ là định dạng nó cho phù hợp với nhu cầu của bạn.

Bước 1: Thêm "vào #temp" vào truy vấn đầu ra (ví dụ: "chọn [...] vào #temp từ [...]").

Cách dễ nhất là trực tiếp chỉnh sửa truy vấn đầu ra trong Proc. nếu bạn không thể thay đổi Proc được lưu trữ, bạn có thể sao chép nội dung vào cửa sổ truy vấn mới và sửa đổi truy vấn tại đó.

Bước 2: Chạy sp_help trên bảng tạm thời. (ví dụ: "exec tempdb..sp_help #temp")

Sau khi tạo bảng tạm thời, hãy chạy sp_help trên bảng tạm thời để có danh sách các cột và loại dữ liệu bao gồm kích thước của các trường varchar.

Bước 3: Sao chép các cột và kiểu dữ liệu vào câu lệnh tạo bảng

Tôi có một bảng Excel mà tôi sử dụng để định dạng đầu ra của sp_help thành câu lệnh "tạo bảng". Bạn không cần bất cứ thứ gì ưa thích, chỉ cần sao chép và dán vào trình soạn thảo SQL của bạn. Sử dụng tên cột, kích thước và loại để xây dựng câu lệnh "Tạo bảng #x [...]" hoặc "khai báo bảng @x [...]" mà bạn có thể sử dụng để XÁC NHẬN kết quả của thủ tục được lưu trữ.

Bước 4: Chèn vào bảng vừa tạo

Bây giờ bạn sẽ có một truy vấn giống như các giải pháp khác được mô tả trong chuỗi này.

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

INSERT INTO @t 
Exec spMyProc 

Kỹ thuật này cũng có thể được sử dụng để chuyển đổi bảng tạm thời ( #temp) thành biến bảng ( @temp). Mặc dù đây có thể là nhiều bước hơn là chỉ tự viết create tablecâu lệnh, nhưng nó ngăn ngừa lỗi thủ công như lỗi chính tả và kiểu dữ liệu không khớp trong các quy trình lớn. Việc sửa lỗi một lỗi đánh máy có thể mất nhiều thời gian hơn so với việc viết truy vấn ở vị trí đầu tiên.


37

Nếu OPENWAYSET gây ra sự cố cho bạn, có một cách khác từ năm 2012 trở đi; sử dụng sys.dm_exec_describe_first_result_set_for_object, như đã đề cập ở đây: Truy xuất tên cột và loại thủ tục được lưu trữ?

Đầu tiên, tạo thủ tục được lưu trữ này để tạo SQL cho bảng tạm thời:

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

Để sử dụng thủ tục, hãy gọi nó theo cách sau:

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

Lưu ý rằng tôi đang sử dụng bảng tạm thời toàn cầu. Đó là bởi vì sử dụng EXEC để chạy SQL động tạo phiên riêng của nó, do đó, một bảng tạm thời thông thường sẽ nằm ngoài phạm vi của bất kỳ mã tiếp theo nào. Nếu một bảng tạm thời toàn cầu là một vấn đề, bạn có thể sử dụng một bảng tạm thời thông thường, nhưng bất kỳ SQL tiếp theo nào cũng cần phải là động, nghĩa là, cũng được thực thi bởi câu lệnh EXEC.


4
Bạn đã quên tạo bảng từ @SQL.
Trisped

32

Quassnoi đưa tôi đến gần đó, nhưng thiếu một điều:

**** Tôi cần sử dụng các tham số trong quy trình được lưu trữ. ****

Và OPENQUERY không cho phép điều này xảy ra:

Vì vậy, tôi đã tìm ra một cách để làm việc với hệ thống và cũng không phải làm cho định nghĩa bảng quá cứng nhắc và xác định lại nó trong một thủ tục được lưu trữ khác (và tất nhiên là có khả năng nó có thể bị hỏng)!

Có, bạn có thể tự động tạo định nghĩa bảng được trả về từ thủ tục được lưu trữ bằng cách sử dụng câu lệnh OPENQUERY với các biến thể không có thật (miễn là NO RESULT SET trả về cùng số lượng trường và ở cùng vị trí với bộ dữ liệu có dữ liệu tốt).

Khi bảng được tạo, bạn có thể sử dụng thủ tục lưu trữ exec vào bảng tạm thời cả ngày.


Và để lưu ý (như đã nêu ở trên), bạn phải kích hoạt quyền truy cập dữ liệu,

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

Mã số:

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

Cảm ơn thông tin được cung cấp ban đầu ... Vâng, cuối cùng tôi cũng không cần phải tạo ra tất cả những giả defintions (chặt chẽ) bảng khi sử dụng dữ liệu từ một thủ tục lưu trữ hoặc cơ sở dữ liệu, và bạn có thể sử dụng các thông số quá.

Tìm kiếm thẻ tham khảo:

  • Quy trình lưu trữ SQL 2005 vào bảng tạm thời

  • openquery với thủ tục lưu trữ và các biến 2005

  • openquery với các biến

  • thực hiện thủ tục lưu trữ vào bảng tạm thời

Cập nhật: điều này sẽ không hoạt động với các bảng tạm thời vì vậy tôi đã phải dùng đến cách tự tạo bảng tạm thời.

Thông báo Bummer : điều này sẽ không hoạt động với các bảng tạm thời , http://www.sommarskog.se/share_data.html#OPENQUERY

Tham khảo: Điều tiếp theo là xác định LOCALSERVER. Nó có thể trông giống như một từ khóa trong ví dụ, nhưng thực tế nó chỉ là một cái tên. Đây là cách bạn làm điều đó:

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

Để tạo một máy chủ được liên kết, bạn phải có quyền ALTER ANY SERVER hoặc là thành viên của bất kỳ vai trò máy chủ cố định nào sysadmin hoặc setupadmin.

OPENQUERY mở một kết nối mới tới SQL Server. Điều này có một số hàm ý:

Quy trình mà bạn gọi bằng OPENQUERY không thể tham chiếu các bảng tạm thời được tạo trong kết nối hiện tại.

Kết nối mới có cơ sở dữ liệu mặc định riêng (được xác định bằng sp_addlinkbederver, mặc định là chính), vì vậy tất cả các đặc tả đối tượng phải bao gồm tên cơ sở dữ liệu.

Nếu bạn có một giao dịch mở và đang giữ các khóa khi bạn gọi OPENQUERY, quy trình được gọi không thể truy cập vào những gì bạn khóa. Đó là, nếu bạn không cẩn thận, bạn sẽ tự chặn mình.

Kết nối không phải là miễn phí, do đó có một hình phạt hiệu suất.


1
Nếu bạn không biết tên máy chủ của mình, hãy sử dụng SELECT @@SERVERNAME. Bạn cũng có thể sử dụngEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Contango

24

Nếu bạn đủ may mắn để có SQL 2012 trở lên, bạn có thể sử dụng dm_exec_describe_first_result_set_for_object

Tôi vừa chỉnh sửa sql được cung cấp bởi gotqn. Cảm ơn gotqn.

Điều này tạo ra một bảng tạm thời toàn cầu với tên giống như tên thủ tục. Bảng tạm thời sau đó có thể được sử dụng theo yêu cầu. Chỉ cần đừng quên thả nó trước khi thực hiện lại.

    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
Thông minh! Chỉ cần một lưu ý: sử dụng sys.all_objectsthay vì sys.proceduresnếu bạn muốn làm điều này cho các thủ tục được lưu trữ tích hợp.
Gert Arnold

2
Điều này cũng sẽ thất bại nếu SP sử dụng các bảng tạm thời bên trong nó. (nhưng nó khá tiện dụng để có được điều này như là một Proc trong kho vũ khí của bạn)
Trub

23

Proc lưu trữ này thực hiện công việc:

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

Đây là một công việc nhỏ của việc này: Chèn kết quả thủ tục được lưu trữ vào bảng để nó thực sự hoạt động.

Nếu bạn muốn nó hoạt động với một bảng tạm thời thì bạn sẽ cần sử dụng một ##GLOBALbảng và thả nó sau đó.


17

Để chèn tập bản ghi đầu tiên của một thủ tục được lưu vào một bảng tạm thời, bạn cần biết những điều sau:

  1. chỉ bộ hàng đầu tiên của thủ tục được lưu trữ có thể được chèn vào một bảng tạm thời
  2. thủ tục được lưu trữ không được thực thi câu lệnh T-SQL động ( sp_executesql)
  3. bạn cần xác định cấu trúc của bảng tạm thời trước

Những điều trên có thể có vẻ hạn chế, nhưng IMHO hoàn toàn có ý nghĩa - nếu bạn đang sử dụng, sp_executesqlbạn có thể trả lại hai cột và một lần mười và nếu bạn có nhiều tập kết quả, bạn cũng không thể chèn chúng vào nhiều bảng - bạn có thể chèn tối đa trong hai bảng trong một câu lệnh T-SQL (sử dụng OUTPUTmệnh đề và không có kích hoạt).

Vì vậy, vấn đề chủ yếu là làm thế nào để xác định cấu trúc bảng tạm thời trước khi thực hiện EXEC ... INTO ...câu lệnh.

Cái đầu tiên hoạt động OBJECT_IDtrong khi cái thứ hai và thứ ba cũng hoạt động với các truy vấn Ad-hoc. Tôi thích sử dụng DMV thay vì sp vì bạn có thể sử dụng CROSS APPLYvà xây dựng các định nghĩa bảng tạm thời cho nhiều thủ tục cùng một lúc.

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;

Ngoài ra, hãy chú ý đến system_type_namelĩnh vực này vì nó có thể rất hữu ích. Nó lưu trữ định nghĩa cột hoàn chỉnh. Ví dụ:

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

và bạn có thể sử dụng nó trực tiếp trong hầu hết các trường hợp để tạo định nghĩa bảng.

Vì vậy, tôi nghĩ rằng trong hầu hết các trường hợp (nếu thủ tục được lưu trữ phù hợp với tiêu chí nhất định), bạn có thể dễ dàng xây dựng các câu lệnh động để giải quyết các vấn đề đó (tạo bảng tạm thời, chèn kết quả thủ tục được lưu trữ vào đó, làm những gì bạn cần với dữ liệu) .


Lưu ý rằng các đối tượng ở trên không xác định dữ liệu tập kết quả đầu tiên trong một số trường hợp như khi các câu lệnh T-SQL động được thực thi hoặc các bảng tạm thời được sử dụng trong thủ tục được lưu trữ.


Quan sát thực tế về các hạn chế: nếu bạn phải chèn đầu ra của một số sp (hãy gọi nó là SP_LEVEL_0) để tạo bảng tạm thời được tạo động bằng cách sử dụng phương pháp trên trong một sp khác (hãy gọi nó là SP_LEVEL_1), bạn không thể thực hiện cùng một mẹo cho đầu ra của SP_LEVEL_1 này một số bảng tạm thời khác trong SP_LEVEL_2
nahab

17
  1. Tôi đang tạo một bảng với lược đồ và dữ liệu sau đây.
  2. Tạo một thủ tục lưu trữ.
  3. Bây giờ tôi biết kết quả của thủ tục là gì, vì vậy tôi đang thực hiện truy vấn sau.

    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

    GIÁ TRỊ (10, 5, 1, NULL) THIẾT LẬP IDENTITY_INSERT [dbo]. [TblTestingTree] Bật

    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

Nếu truy vấn không chứa tham số, sử dụng sử dụng OpenQuerykhác OpenRowset.

Điều cơ bản sẽ là tạo lược đồ theo thủ tục được lưu trữ và chèn vào bảng đó. ví dụ:

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

Tôi hi vọng cái này giúp được. Vui lòng đủ điều kiện khi thích hợp.


11

Tôi đã tìm thấy Chuyển các mảng / dữ liệu vào các thủ tục được lưu trữ có thể cho bạn một ý tưởng khác về cách bạn có thể giải quyết vấn đề của mình.

Liên kết gợi ý sử dụng tham số loại Ảnh để chuyển vào thủ tục được lưu trữ. Sau đó, trong thủ tục được lưu trữ, hình ảnh được chuyển thành một biến bảng chứa dữ liệu gốc.

Có lẽ có một cách này có thể được sử dụng với một bảng tạm thời.


4
Điều này không còn cần thiết trong các phiên bản Sql2008 trở lên với việc giới thiệu Tham số Giá trị Bảng . Bây giờ bạn có thể trực tiếp chuyển một tập dữ liệu .net hoặc đối tượng có thể truy cập vào một thủ tục được lưu trữ sql với việc phải chuyển đổi thành byte như được đề cập trong liên kết ở trên
EndlessSpace

10

Tôi đã gặp vấn đề tương tự và đây là những gì tôi đã làm cho điều này từ đề nghị của Paul . Phần chính ở đây là để sử dụng NEWID()để tránh nhiều người dùng chạy các thủ tục / tập lệnh của cửa hàng cùng một lúc, nỗi đau cho bảng tạm thời toàn cầu.

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

Một phương pháp khác là tạo một loại và sử dụng PIPELINED để sau đó trả lại đối tượng của bạn. Điều này được giới hạn để biết các cột tuy nhiên. Nhưng nó có lợi thế là có thể làm được:

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

Cái này là cái gì? Dường như không có gì để làm với SQL Server mà câu hỏi này là về
Martin Smith

8

Đó là quy trình 2 bước đơn giản: - tạo bảng tạm thời - Chèn vào bảng tạm thời.

Mã để thực hiện tương tự:

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

Xuống cấp; rất giống với câu trả lời hiện có.
iokevins

6

Sau khi tìm kiếm xung quanh, tôi đã tìm ra cách tạo bảng tạm thời cho bất kỳ thủ tục được lưu trữ nào mà không sử dụng OPENROWSEThoặc OPENQUERYsử dụng lược đồ chung về định nghĩa kết quả của Quy trình được lưu trữ, đặc biệt khi bạn không phải là Quản trị viên cơ sở dữ liệu.

Máy chủ Sql có một buit-in Proc sp_describe_first_result_setcó thể cung cấp cho bạn lược đồ của bất kỳ kết quả thủ tục nào. Tôi đã tạo một bảng lược đồ từ kết quả của thủ tục này và tự đặt tất cả các trường thành 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 

Được phát triển và thử nghiệm trên phiên bản Sql Server - Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (Bản dựng 17134 :)

Bạn có thể điều chỉnh lược đồ cho phiên bản máy chủ SQL mà bạn đang sử dụng (nếu cần).


4

Nếu bạn biết các tham số đang được thông qua và nếu bạn không có quyền truy cập để tạo sp_cool, thì hãy chỉnh sửa quy trình được lưu trữ với các tham số này và điều tương tự có thể được lưu trữ trong bảng toàn cầu ##.


3

Điều này có thể được thực hiện trong SQL Server 2014+ với điều kiện thủ tục được lưu trữ chỉ trả về một bảng. Nếu bất cứ ai tìm thấy cách làm điều này cho nhiều bảng tôi muốn biết về nó.

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

Điều này kéo định nghĩa của bảng trả về từ các bảng hệ thống và sử dụng định nghĩa đó để xây dựng bảng tạm thời cho bạn. Sau đó, bạn có thể điền nó từ thủ tục được lưu trữ như đã nêu trước đó.

Ngoài ra còn có các biến thể của điều này cũng hoạt động với Dynamic SQL.


2

Một vài năm muộn cho câu hỏi, nhưng tôi cần một cái gì đó như thế này để tạo mã nhanh và bẩn. Tôi tin như những người khác đã tuyên bố rằng việc xác định bảng tạm thời trở nên dễ dàng hơn, nhưng phương pháp này sẽ hoạt động đối với các truy vấn thủ tục được lưu trữ đơn giản hoặc các biểu tượng sql.

Điều này sẽ hơi phức tạp, nhưng nó mượn từ những người đóng góp ở đây cũng như giải pháp của Paul White từ DBA Stack Exchange Nhận các loại cột kết quả thủ tục được lưu trữ . Một lần nữa, để nhắc lại cách tiếp cận & ví dụ này không được thiết kế cho các quy trình trong môi trường nhiều người dùng. Trong trường hợp này, định nghĩa bảng đang được đặt trong một thời gian ngắn trong bảng tạm thời toàn cầu để tham chiếu theo quy trình mẫu tạo mã.

Tôi chưa kiểm tra đầy đủ điều này để có thể có những cảnh báo vì vậy bạn có thể muốn truy cập liên kết MSDN trong câu trả lời của Paul White. Điều này áp dụng cho SQL 2012 trở lên.

Trước tiên, hãy sử dụng thủ tục được lưu trữ sp_describe_first_result_set giống với mô tả của Oracle.

Điều này sẽ đánh giá hàng đầu tiên của tập kết quả đầu tiên để nếu thủ tục hoặc câu lệnh được lưu trữ của bạn trả về nhiều truy vấn, nó sẽ chỉ mô tả kết quả đầu tiên.

Tôi đã tạo một Proc được lưu trữ để chia nhỏ các tác vụ trả về một trường duy nhất để chọn từ đó để tạo định nghĩa bảng tạm thời.

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

Câu hỏi hóc búa là bạn cần sử dụng bảng toàn cầu, nhưng bạn cần làm cho nó đủ độc đáo để bạn có thể thả và tạo từ nó thường xuyên mà không lo bị va chạm.
Trong ví dụ này, tôi đã sử dụng một Hướng dẫn (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) cho biến toàn cục thay thế dấu gạch nối bằng dấu gạch dưới

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

Một lần nữa, tôi chỉ kiểm tra nó với các truy vấn thủ tục được lưu trữ đơn giản và các truy vấn đơn giản để số dặm của bạn có thể thay đổi. Hy vọng điều này sẽ giúp được ai đó.


1

Chà, bạn phải tạo một bảng tạm thời, nhưng nó không phải có lược đồ đúng .... Tôi đã tạo một quy trình được lưu trữ để sửa đổi bảng tạm thời hiện có để nó có các cột cần thiết với dữ liệu phù hợp loại và thứ tự (bỏ tất cả các cột hiện có, thêm các cột mới):

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

Lưu ý điều này sẽ không hoạt động nếu sys.dm_exec_describe_first_result_set_for_object không thể xác định kết quả của thủ tục được lưu trữ (ví dụ: nếu nó sử dụng bảng tạm thời).


0

Nếu bạn để SQL động tạo bảng tạm thời, bảng này được sở hữu bởi kết nối SQL động, trái ngược với kết nối mà thủ tục được lưu trữ của bạn được gọi từ.

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;

nhập mô tả hình ảnh ở đây

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;

Msg 208, Cấp 16, Trạng thái 0 Tên đối tượng không hợp lệ '#POLLed'. Điều này là do #POLLed được sở hữu bởi kết nối SQL động. Vì vậy, hướng dẫn cuối cùng

SELECT * FROM #Pivoted

thất bại

Một cách để không phải đối mặt với vấn đề này là đảm bảo tất cả các tham chiếu đến #POLLed được tạo từ bên trong chính truy vấn động:

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

nhập mô tả hình ảnh ở đây


-5

Tôi sẽ làm như sau

  1. Tạo (chuyển đổi SP thành) UDF (Bảng giá trị UDF).

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


2
Có thể có một số tuyên bố thực hiện bước đầu tiên của bạn. Ví dụ, nếu SP gốc sử dụng các bảng tạm thời. UDF không thể sử dụng các bảng tạm thời.
yucer
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.