Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Truy xuất định nghĩa cột cho tập kết quả thủ tục được lưu trữ

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tập tin MDF là gì?

  2. Đích đến của máy chủ SQL so với Đích của OLE DB

  3. THỜI GIAN THỐNG KÊ trong SQL Server là gì?

  4. Gói SSIS không muốn tìm nạp siêu dữ liệu của bảng tạm thời

  5. Cách tốt nhất để triển khai đường mòn kiểm tra trong SQL Server?