Vì vậy, giả sử bạn có một thủ tục được lưu trữ trong tempdb:
USE tempdb;
GO
CREATE PROCEDURE dbo.my_procedure
AS
BEGIN
SET NOCOUNT ON;
SELECT foo = 1, bar = 'tooth';
END
GO
Có một cách khá phức tạp mà bạn có thể thực hiện là xác định siêu dữ liệu mà thủ tục được lưu trữ sẽ xuất ra. Có một số lưu ý, bao gồm cả quy trình chỉ có thể xuất ra một tập kết quả duy nhất và dự đoán tốt nhất sẽ được thực hiện về kiểu dữ liệu nếu không thể xác định chính xác. Nó yêu cầu sử dụng OPENQUERY
và một máy chủ được liên kết lặp lại với 'DATA ACCESS'
thuộc tính được đặt thành true. Bạn có thể kiểm tra sys.servers để xem liệu bạn đã có một máy chủ hợp lệ chưa, nhưng hãy chỉ tạo một máy chủ có tên là loopback
theo cách thủ công :
EXEC master..sp_addlinkedserver
@server = 'loopback',
@srvproduct = '',
@provider = 'SQLNCLI',
@datasrc = @@SERVERNAME;
EXEC master..sp_serveroption
@server = 'loopback',
@optname = 'DATA ACCESS',
@optvalue = 'TRUE';
Bây giờ bạn có thể truy vấn đây là một máy chủ được liên kết, bạn có thể sử dụng kết quả của bất kỳ truy vấn nào (bao gồm cả lệnh gọi thủ tục được lưu trữ) dưới dạng SELECT
thông thường . Vì vậy, bạn có thể làm điều này (lưu ý rằng tiền tố cơ sở dữ liệu là quan trọng, nếu không bạn sẽ gặp lỗi 11529 và 2812):
SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Nếu chúng ta có thể thực hiện SELECT *
, chúng tôi cũng có thể thực hiện SELECT * INTO
:
SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
Và khi bảng #tmp đó tồn tại, chúng ta có thể xác định siêu dữ liệu bằng cách nói (giả sử SQL Server 2005 trở lên):
SELECT c.name, [type] = t.name, c.max_length, c.[precision], c.scale
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE c.[object_id] = OBJECT_ID('tempdb..#tmp');
(Nếu bạn đang sử dụng SQL Server 2000, bạn có thể làm điều gì đó tương tự với cột hệ thống, nhưng tôi không có phiên bản 2000 nào hữu ích để xác thực một truy vấn tương đương.)
Kết quả:
name type max_length precision scale
--------- ------- ---------- --------- -----
foo int 4 10 0
bar varchar 5 0 0
Ở Denali, điều này sẽ dễ dàng hơn rất nhiều. Một lần nữa, vẫn còn một hạn chế của tập kết quả đầu tiên nhưng bạn không phải thiết lập một máy chủ được liên kết và chuyển qua tất cả các vòng đó. Bạn chỉ có thể nói:
DECLARE @sql NVARCHAR(MAX) = N'EXEC tempdb.dbo.my_procedure;';
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set(@sql, NULL, 1);
Kết quả:
name system_type_name
--------- ----------------
foo int
bar varchar(5)
Cho đến tận Denali, tôi khuyên bạn sẽ dễ dàng hơn nếu chỉ cần xắn tay áo lên và tự mình tìm ra các loại dữ liệu. Không chỉ vì việc thực hiện các bước trên tẻ nhạt mà còn vì bạn có nhiều khả năng đưa ra phỏng đoán chính xác (hoặc ít nhất là chính xác hơn) so với dự đoán của động cơ, vì kiểu dữ liệu đoán mà động cơ tạo ra sẽ dựa trên thời gian chạy đầu ra, mà không có bất kỳ kiến thức bên ngoài nào về miền của các giá trị có thể. Yếu tố này cũng sẽ đúng trong Denali, vì vậy đừng có ấn tượng rằng các tính năng khám phá siêu dữ liệu mới là tất cả, chúng chỉ làm cho những điều trên bớt tẻ nhạt hơn một chút.
Ồ và cho một số vấn đề tiềm năng khác với OPENQUERY
, xem bài viết của Erland Sommarskog tại đây:
http://www.sommarskog.se/share_data.html#OPENQUERY