[Saya baru menyadari bahwa saya telah menjawab pertanyaan ini sebelumnya]
Melakukan ini untuk prosedur tersimpan jauh lebih rumit daripada untuk tampilan atau tabel. Salah satu masalahnya adalah bahwa prosedur tersimpan dapat memiliki beberapa jalur kode berbeda tergantung pada parameter input dan bahkan hal-hal yang tidak dapat Anda kendalikan seperti status server, waktu, dll. Jadi misalnya apa yang Anda harapkan sebagai output untuk prosedur tersimpan ini? Bagaimana jika ada banyak hasil, terlepas dari persyaratannya?
CREATE PROCEDURE dbo.foo
@bar INT
AS
BEGIN
SET NOCOUNT ON;
IF @bar = 1
SELECT a, b, c FROM dbo.blat;
ELSE
SELECT d, e, f, g, h FROM dbo.splunge;
END
GO
Jika prosedur tersimpan Anda tidak memiliki jalur kode dan Anda yakin bahwa Anda akan selalu melihat kumpulan hasil yang sama (dan dapat menentukan terlebih dahulu nilai apa yang harus diberikan jika prosedur tersimpan memiliki parameter non-opsional), mari kita ambil contoh sederhana:
CREATE PROCEDURE dbo.bar
AS
BEGIN
SET NOCOUNT ON;
SELECT a = 'a', b = 1, c = GETDATE();
END
GO
HANYA FM
Salah satu caranya adalah dengan melakukan sesuatu seperti ini:
SET FMTONLY ON;
GO
EXEC dbo.bar;
Ini akan memberi Anda kumpulan hasil yang kosong dan aplikasi klien Anda dapat melihat properti kumpulan hasil tersebut untuk menentukan nama kolom dan tipe data.
Sekarang, ada banyak masalah dengan SET FMTONLY ON;
bahwa saya tidak akan membahasnya di sini, tetapi setidaknya perlu dicatat bahwa perintah ini tidak digunakan lagi - untuk alasan yang baik. Juga berhati-hatilah untuk SET FMTONLY OFF;
setelah selesai, atau Anda akan bertanya-tanya mengapa Anda berhasil membuat prosedur tersimpan tetapi kemudian tidak dapat menjalankannya. Dan tidak, saya tidak memperingatkan Anda tentang itu karena itu baru saja terjadi pada saya. Jujur. :-)
BUKA PERMINTAAN
Dengan membuat server tertaut loopback, Anda kemudian dapat menggunakan alat seperti OPENQUERY
untuk menjalankan prosedur tersimpan tetapi mengembalikan hasil yang dapat dikomposisi (yah, terimalah itu sebagai definisi yang sangat longgar) yang dapat Anda periksa. Pertama buat server loopback (ini mengasumsikan instance lokal bernama FOO
):
USE master;
GO
EXEC sp_addlinkedserver @server = N'.\FOO', @srvproduct=N'SQL Server'
GO
EXEC sp_serveroption @server=N'.\FOO', @optname=N'data access',
@optvalue=N'true';
Sekarang kita dapat mengambil prosedur di atas dan memasukkannya ke dalam kueri seperti ini:
SELECT * INTO #t
FROM OPENQUERY([.\FOO], 'EXEC dbname.dbo.bar;')
WHERE 1 = 0;
SELECT c.name, t.name
FROM tempdb.sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
WHERE c.[object_id] = OBJECT_ID('tempdb..#t');
Ini mengabaikan tipe alias (sebelumnya dikenal sebagai tipe data yang ditentukan pengguna) dan juga dapat menampilkan dua baris untuk kolom yang didefinisikan sebagai, misalnya, sysname
. Tapi dari atas menghasilkan:
name name
---- --------
b int
c datetime
a varchar
Jelas ada lebih banyak pekerjaan yang harus dilakukan di sini - varchar
tidak menunjukkan panjang, dan Anda harus mendapatkan presisi/skala untuk jenis lain seperti datetime2
, time
dan decimal
. Tapi itu permulaan.
SQL Server 2012
Ada beberapa fungsi baru di SQL Server 2012 yang membuat penemuan metadata menjadi lebih mudah. Untuk prosedur di atas kita dapat melakukan hal berikut:
SELECT name, system_type_name
FROM sys.dm_exec_describe_first_result_set_for_object
(
OBJECT_ID('dbo.bar'),
NULL
);
Antara lain ini benar-benar memberikan presisi dan skala dan menyelesaikan jenis alias untuk kita. Untuk prosedur di atas ini menghasilkan:
name system_type_name
---- ----------------
a varchar(1)
b int
c datetime
Tidak banyak perbedaan secara visual tetapi ketika Anda mulai masuk ke semua tipe data yang berbeda dengan berbagai presisi dan skala, Anda akan menghargai kerja ekstra yang dilakukan fungsi ini untuk Anda.
Kelemahannya:Di SQL Server 2012 setidaknya fungsi ini hanya berfungsi untuk pertama resultset (sesuai dengan nama fungsinya).