Masukkan hasil dari prosedur tersimpan ke dalam tabel sementara

1579

Bagaimana caranya SELECT * INTO [temp table] FROM [stored procedure]? Tidak FROM [Table]dan tanpa mendefinisikan [temp table]?

Selectsemua data dari BusinessLinedalam tmpBusLinebekerja dengan baik.

select *
into tmpBusLine
from BusinessLine

Saya mencoba yang sama, tetapi menggunakan stored procedureyang mengembalikan data, tidak persis sama.

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

Pesan keluaran:

Msg 156, Level 15, Status 1, Baris 2 Sintaks salah di dekat kata kunci 'exec'.

Saya telah membaca beberapa contoh membuat tabel sementara dengan struktur yang sama dengan prosedur tersimpan tersimpan, yang berfungsi dengan baik, tetapi alangkah baiknya jika tidak menyediakan kolom apa pun.

Ferdeen
sumber
22
Dengan SELECT * INTO [NAMA TABEL] Anda tahu kolom, karena mereka disalin dari tabel asli. Inilah yang saya inginkan jika saya melakukan hal yang sama terhadap prosedur tersimpan.
Ferdeen
7
Hanya ingin menunjukkan bahwa "pilih * ke tmpBusLine" membuat tabel permanen. Anda mungkin ingin "pilih * ke #tmpBusLine". Saya yakin poster asli telah menemukan ini, tetapi mungkin membantu orang lain yang menemukan posting ini karena ini adalah hasil teratas saat ini untuk pencarian "pilih ke tabel temp"
ktam33
2
Saya tidak tahu apakah ini telah diatasi atau tidak tetapi alasan mengapa Anda mendapatkan kesalahan adalah karena dari kata kunci.
Wes Palmer
9
Microsoft perlu menambahkan SELECT * INTO FROM EXEC! Silahkan!
kjmerf

Jawaban:

704

Anda dapat menggunakan OPENROWSET untuk ini. Silahkan lihat. Saya juga menyertakan kode sp_configure untuk mengaktifkan Kueri Terdistribusi Ad Hoc, jika belum diaktifkan.

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
Aaron Alton
sumber
28
Ini cara yang tepat untuk melakukannya. OPENROWSET adalah satu-satunya cara untuk memperlakukan hasil dari prosedur tersimpan sebagai ekspresi tabel.
Rob Farley
37
Ini tampaknya agak rumit hanya untuk dimasukkan ke dalam tabel. Banyak konfigurasi yang harus dilakukan. Juga ketika saya mencobanya saya mendapat "Msg 7357, Level 16, Negara 2, Baris 1 Tidak dapat memproses objek" EXEC GetPartyAnalysisData 146 ". Penyedia OLE DB" SQLNCLI "untuk server tertaut" (null) "menunjukkan bahwa salah satu objek memiliki tidak ada kolom atau pengguna saat ini tidak memiliki izin pada objek itu. " Jadi, Anda perlu mengatur server yang terhubung ...
Ferdeen
10
Anda tidak memerlukan server yang ditautkan, tetapi Anda harus mendapatkan string koneksi dengan benar ... dan juga, tentukan path lengkap ke prosedur tersimpan termasuk nama database dan pemilik sp.
MartW
18
eeeeew! referensi ke server yang sama? menjijikan. jelas lebih merupakan peretasan daripada harus secara manual membuat tabel temp
Tim Abell
23
Saya setuju bahwa ini adalah peretasan dan mungkin harus dihindari kecuali punggung Anda menempel ke dinding. Mengubah sp ke fungsi mungkin merupakan sudut yang lebih baik untuk diambil. MENURUT OPINI SAYA.
greg
624

Jika Anda ingin melakukannya tanpa terlebih dahulu mendeklarasikan tabel sementara, Anda bisa mencoba membuat fungsi yang ditentukan pengguna daripada prosedur yang disimpan dan membuat fungsi yang ditentukan pengguna mengembalikan tabel. Atau, jika Anda ingin menggunakan prosedur tersimpan, coba sesuatu seperti ini:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'
Gavin
sumber
171
Saya pikir intinya adalah untuk menghasilkan skema tanpa harus secara eksplisit menyatakannya.
Craig
5
Saya akan tertarik untuk mengetahui apa perbedaan antara ini dan solusi @Aaron Alton di atas. Yang ini tampaknya jauh lebih sederhana, tetapi saya tidak yakin dengan implikasi lain.
funkymushroom
11
Ini akan berfungsi tetapi jika Anda pernah menambahkan kolom tambahan ke prosedur tersimpan SpGetRecords, ini akan meledak.
Brady Holt
15
Anda hanya mendapatkan satu INSERT INTO EXEC per tumpukan panggilan. SpGetRecords dan proc lainnya yang dihubungi tidak boleh menggunakan strategi ini dalam kode mereka sendiri. Ini dapat mengejutkan pengelola SpGetRecords.
Matt Stephenson
33
Ini tidak menjawab pertanyaan sama sekali dan saya tidak melihat mengapa hal itu begitu terangkat? OP secara eksplisit menyatakan "tanpa mendefinisikan [temp table]" dan baris pertama Anda memiliki pernyataan create temp table.
NickG
296

Di SQL Server 2005 Anda bisa menggunakan INSERT INTO ... EXECuntuk memasukkan hasil dari prosedur tersimpan ke dalam tabel. Dari dokumentasi MSDNINSERT (untuk SQL Server 2000, sebenarnya):

--INSERT...EXECUTE procedure example
INSERT author_sales EXECUTE get_author_sales
Matt Hamilton
sumber
122
Ini membutuhkan pengarang_sales untuk didefinisikan di muka. Saya berusaha menghindari ini. Terima kasih.
Ferdeen
5
Saya banyak berpikir. Sangat berguna Memasukkan ke dalam tabel tmp dengan cepat, tetapi tidak begitu berguna jika Anda perlu mengetahui struktur dataset yang dikembalikan dari proc yang disimpan. Terima kasih atas bantuannya.
Ferdeen
3
Ada artikel bagus di sini msdn.microsoft.com/en-us/library/aa175921.aspx
Rich Andrews
4
Untuk menggunakan skema yang sama, Anda dapat membuat salinan sebagai berikut: pilih top 0 * ke tempTable dari realTable ( stackoverflow.com/a/9206463/73794 )
Even Mien
@EvenMien Saya sejenak merasa senang ketika saya melihat komentar Anda ... tapi sayangnya itu hanya bekerja jika hasil dari proc Anda benar-benar mencerminkan tabel nyata :(
BVernon
193

Ini adalah jawaban untuk versi pertanyaan Anda yang sedikit dimodifikasi. Jika Anda dapat mengabaikan penggunaan prosedur tersimpan untuk fungsi yang ditentukan pengguna, Anda dapat menggunakan fungsi yang ditentukan pengguna yang ditentukan tabel inline. Ini pada dasarnya adalah prosedur tersimpan (akan mengambil parameter) yang mengembalikan tabel sebagai hasil yang ditetapkan; dan karena itu akan cocok dengan pernyataan INTO.

Berikut ini adalah artikel cepat yang bagus dan fungsi-fungsi yang ditentukan pengguna lainnya. Jika Anda masih memiliki kebutuhan mengemudi untuk prosedur tersimpan, Anda bisa membungkus fungsi yang ditentukan pengguna dengan nilai tabel inline dengan prosedur tersimpan. Prosedur tersimpan hanya melewati parameter ketika ia memanggil pilih * dari fungsi yang ditentukan pengguna yang ditentukan tabel inline.

Jadi misalnya, Anda akan memiliki fungsi yang ditentukan pengguna dengan nilai tabel inline untuk mendapatkan daftar pelanggan untuk wilayah tertentu:

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

Anda kemudian dapat memanggil fungsi ini untuk mendapatkan hasil seperti apa:

SELECT * FROM CustomersbyRegion(1)

Atau untuk melakukan SELECT INTO:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Jika Anda masih membutuhkan prosedur tersimpan, maka bungkus fungsinya seperti ini:

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

Saya pikir ini adalah metode yang paling 'hack-less' untuk mendapatkan hasil yang diinginkan. Ini menggunakan fitur yang ada karena mereka dimaksudkan untuk digunakan tanpa komplikasi tambahan. Dengan menumpuk fungsi yang ditentukan pengguna yang dinilai tabel inline dalam prosedur tersimpan, Anda memiliki akses ke fungsionalitas dalam dua cara. Plus! Anda hanya memiliki satu titik pemeliharaan untuk kode SQL yang sebenarnya.

Penggunaan OPENROWSET telah disarankan, tetapi ini bukan tujuan dari fungsi OPENROWSET untuk digunakan (Dari Buku Daring):

Termasuk semua informasi koneksi yang diperlukan untuk mengakses data jarak jauh dari sumber data OLE DB. Metode ini merupakan alternatif untuk mengakses tabel di server yang ditautkan dan merupakan metode ad-hoc satu kali untuk menghubungkan dan mengakses data jarak jauh dengan menggunakan OLE DB. Untuk referensi yang lebih sering ke sumber data OLE DB, gunakan server yang ditautkan.

Menggunakan OPENROWSET akan menyelesaikan pekerjaan, tetapi itu akan menimbulkan beberapa biaya tambahan untuk membuka koneksi lokal dan menyusun data. Ini juga mungkin tidak menjadi pilihan dalam semua kasus karena memerlukan izin permintaan ad hoc yang menimbulkan risiko keamanan dan karenanya mungkin tidak diinginkan. Juga, pendekatan OPENROWSET akan menghalangi penggunaan prosedur tersimpan yang mengembalikan lebih dari satu set hasil. Membungkus beberapa inline table-nilai fungsi yang ditentukan pengguna dalam satu prosedur tersimpan dapat mencapai ini.

Christian Loris
sumber
4
+1 Fungsi bernilai tabel adalah solusi yang tepat. Kita harus mencatat kelemahan minor: fungsi bernilai tabel adalah objek basis data tambahan, dan mungkin perlu untuk memberikan hak istimewa padanya.
spencer7593
2
Cinta solusinya. Satu halangan kecil yang saya tekan, adalah bahwa meja saya tidak dapat dipesan di mana karena dapat disimpan dalam prosedur tersimpan. Baiklah, saya akan mengatasinya
mrwaim
5
Satu lagi hambatan - "Tidak dapat mengakses tabel sementara dari dalam suatu fungsi"
mrwaim
7
Pertanyaan aslinya adalah bagaimana kita membuat tabel temp dengan hasil dari sp. Ini adalah pola yang baik, tetapi tidak menjawab pertanyaan ini
greg
16
greg, baris pertama dalam jawaban saya menyatakan "Ini adalah jawaban untuk versi pertanyaan Anda yang sedikit dimodifikasi." Komentar Anda berlebihan.
Christian Loris
131
EXEC sp_serveroption 'YOURSERVERNAME', 'DATA ACCESS', TRUE

SELECT  *
INTO    #tmpTable
FROM    OPENQUERY(YOURSERVERNAME, 'EXEC db.schema.sproc 1')
Quassnoi
sumber
2
Dapatkan "Msg 208, Level 16, State 1, Line 1 Nama objek tidak valid 'tmpBusLine' (mungkin karena tidak
ditentukan di
1
@Ferds: maaf, awalnya tidak mengerti permintaan Anda. Diperbarui dengan solusi lain.
Quassnoi
26
Solusi bagus Satu peringatan, Anda harus mengaktifkan 'DATA ACCESS' di server Anda: EXEC sp_serveroption 'TheServerName', 'DATA ACCESS', TRUE
jcollum
8
Anda juga harus mengizinkan akses jarak jauh ke server. Ini akan memiliki konsekuensi keamanan.
BraveNewMath
7
Ini tidak akan berfungsi jika prosedur yang disimpan target menggunakan tabel temp
Sal
125

Solusi termudah:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Jika Anda tidak mengetahui skema tersebut maka Anda dapat melakukan hal berikut. Harap dicatat bahwa ada risiko keamanan yang parah dalam metode ini.

SELECT * 
INTO #temp
FROM OPENROWSET('SQLNCLI', 
                'Server=localhost;Trusted_Connection=yes;', 
                'EXEC [db].[schema].[sproc]')
Tigerjz32
sumber
jika saya tidak tahu kolom hasil yang dikembalikan lalu ??? maksud saya kolom dapat bervariasi. jadi bagaimana cara memasukkan hasilnya ke tabel temp ???
SHEKHAR SHETE
Anda dapat menggunakan OPENQUERY tetapi tidak disarankan karena dilengkapi dengan kelemahan keamanan.
Tigerjz32
1
"Jika saya tidak tahu kolom hasil yang dikembalikan maka" maka Anda tidak dapat menggunakannya dalam logika Anda. Bagaimana Anda akan menggunakan data jika Anda tidak tahu apa itu?
Adriaan Davel
@AdriaanDavel Saya setuju dengan Anda bahwa Anda harus selalu tahu data Anda (praktik terbaik), namun apa yang mungkin ia katakan adalah bahwa ada saat ketika sproc mengembalikan kolom dinamis dan Anda tidak selalu tahu seperti apa skema tersebut. Dalam hal ini, Anda dapat menggunakan OPENROWSET untuk menyisipkan dan membuat tabel dengan cepat. Namun, ada risiko keamanan yang jelas dengan melakukan ini ...
Tigerjz32
1
@nurettin kadang-kadang Anda tidak tahu prosedur tersimpan apa yang akan dikembalikan. Apa yang terjadi dalam kasus itu? Bagaimana Anda bisa membuat tabel temp (ketika Anda tidak tahu apa prosedur yang tersimpan akan kembali) dan memasukkannya dari prosedur yang tersimpan?
Tigerjz32
106

Ketika prosedur tersimpan mengembalikan banyak kolom dan Anda tidak ingin secara manual "membuat" tabel sementara untuk menampung hasilnya, saya telah menemukan cara termudah untuk masuk ke prosedur tersimpan dan menambahkan "menjadi" klausa pada pernyataan pilih terakhir dan tambahkan 1 = 0 ke klausa di mana.

Jalankan prosedur tersimpan sekali dan kembali dan menghapus kode SQL yang baru saja Anda tambahkan. Sekarang, Anda akan memiliki tabel kosong yang cocok dengan hasil prosedur tersimpan. Anda bisa "skrip tabel sebagai buat" untuk tabel sementara atau cukup masukkan langsung ke tabel itu.

dotjoe
sumber
9
+1, saran yang bagus. Anda bahkan bisa menambahkan variabel opsional cepat ke sproc bernama @TableCreate atau yang serupa ketika tidak null lakukan langkah-langkah di atas. Tidak perlu mengubah sproc kemudian setelah diatur.
Ian Roke
1
@ dojjoe Apakah Anda melakukan SELECT INTOtabel temp dan melakukan tabel skrip sebagai buat dari tabel temp? Tabel temp muncul tempdbtetapi saya tidak dapat melakukan klik kanan dan membuat skrip buat. Bantuan apa pun dihargai.
DotnetDude
2
@DotNetDude Anda dapat select ... into new_tablesecara implisit membuat tabel aktual.
dotjoe
Kemudian ambil definisi kolom kasar dari skema tabel kosong; ganti '...' di akhir dengan TABLE_NAME yang sah: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
Ini solusi terbaik!
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;
nitin
sumber
3
tidak menjawab pertanyaan awal OP, melakukan penyisipan tanpa menentukan tabel temp terlebih dahulu.
t.terden
48

Apakah prosedur tersimpan Anda hanya mengambil data atau memodifikasinya juga? Jika hanya digunakan untuk mengambil, Anda dapat mengubah prosedur tersimpan menjadi fungsi dan menggunakan Common Table Expressions (CTEs) tanpa harus menyatakannya, sebagai berikut:

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

Namun, apa pun yang perlu diambil dari CTE harus digunakan dalam satu pernyataan saja. Anda tidak dapat melakukan with temp as ...dan mencoba menggunakannya setelah beberapa baris SQL. Anda dapat memiliki beberapa CTE dalam satu pernyataan untuk kueri yang lebih kompleks.

Sebagai contoh,

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)
JADI Pengguna
sumber
1
Ini bukan tabel sementara, adalah CTE. technet.microsoft.com/en-us/library/...
yucer
5
Terima kasih @yucer ... Saya yakin saya tidak tahu mereka dipanggil CTE dulu :)
SO Pengguna
48

Jika tabel hasil proc yang disimpan terlalu rumit untuk mengetikkan pernyataan "buat tabel" dengan tangan, dan Anda tidak bisa menggunakan OPENQUERY ATAU OPENROWSET, Anda bisa menggunakan sp_help untuk membuat daftar kolom dan tipe data untuk Anda. Setelah Anda memiliki daftar kolom, tinggal memformatnya sesuai dengan kebutuhan Anda.

Langkah 1: Tambahkan "ke #temp" ke kueri keluaran (mis. "Pilih [...] ke #temp dari [...]").

Cara termudah adalah mengedit kueri keluaran di proc secara langsung. jika Anda tidak dapat mengubah proc yang disimpan, Anda dapat menyalin konten ke jendela permintaan baru dan memodifikasi permintaan di sana.

Langkah 2: Jalankan sp_help di tabel temp. (mis. "exec tempdb..sp_help #temp")

Setelah membuat tabel temp, jalankan sp_help di tabel temp untuk mendapatkan daftar kolom dan tipe data termasuk ukuran bidang varchar.

Langkah 3: Salin kolom & tipe data ke dalam pernyataan tabel buat

Saya memiliki lembar Excel yang saya gunakan untuk memformat output sp_help menjadi pernyataan "buat tabel". Anda tidak perlu sesuatu yang mewah, cukup salin dan tempel ke editor SQL Anda. Gunakan nama kolom, ukuran, dan jenis untuk membangun pernyataan "Buat tabel #x [...]" atau "nyatakan @x tabel [...]" yang dapat Anda gunakan untuk menyisipkan hasil dari prosedur tersimpan.

Langkah 4: Masukkan ke dalam tabel yang baru dibuat

Sekarang Anda akan memiliki kueri yang seperti solusi lain yang dijelaskan di utas ini.

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

INSERT INTO @t 
Exec spMyProc 

Teknik ini juga dapat digunakan untuk mengonversi tabel temp ( #temp) ke variabel tabel ( @temp). Meskipun ini mungkin lebih banyak langkah daripada hanya menulis create tablepernyataan sendiri, itu mencegah kesalahan manual seperti kesalahan ketik dan tipe data dalam proses besar. Mendebug kesalahan ketik bisa memakan waktu lebih lama daripada menulis kueri di tempat pertama.

Tinjuan kemarahan
sumber
37

Jika OPENROWSET menyebabkan Anda mengalami masalah, ada cara lain mulai 2012 dan seterusnya; memanfaatkan sys.dm_exec_describe_first_result_set_for_object, seperti yang disebutkan di sini: Ambil nama kolom dan jenis prosedur tersimpan?

Pertama, buat prosedur tersimpan ini untuk menghasilkan SQL untuk tabel sementara:

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

Untuk menggunakan prosedur, panggil dengan cara berikut:

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

Perhatikan bahwa saya menggunakan tabel sementara global. Itu karena menggunakan EXEC untuk menjalankan SQL dinamis membuat sesi sendiri, sehingga tabel sementara biasa akan berada di luar jangkauan ke kode berikutnya. Jika tabel sementara global adalah masalah, Anda bisa menggunakan tabel sementara biasa, tetapi setiap SQL berikutnya harus dinamis, yaitu, juga dieksekusi oleh pernyataan EXEC.

StuartQ
sumber
4
Anda lupa membuat tabel dari @SQL.
Dipotong
32

Quassnoi menempatkan saya hampir di sana, tetapi satu hal hilang:

**** Saya perlu menggunakan parameter dalam prosedur tersimpan. ****

Dan OPENQUERY tidak mengizinkan ini terjadi:

Jadi saya menemukan cara untuk bekerja sistem dan juga tidak harus membuat definisi tabel begitu kaku, dan mendefinisikannya kembali di dalam prosedur lain yang tersimpan (dan tentu saja mengambil kesempatan itu mungkin rusak)!

Ya, Anda dapat secara dinamis membuat definisi tabel yang dikembalikan dari prosedur tersimpan dengan menggunakan pernyataan OPENQUERY dengan variabel palsu (selama NO SET HASIL mengembalikan jumlah bidang yang sama dan dalam posisi yang sama dengan dataset dengan data yang baik).

Setelah tabel dibuat, Anda dapat menggunakan prosedur tersimpan exec ke dalam tabel sementara sepanjang hari.


Dan untuk dicatat (seperti yang ditunjukkan di atas) Anda harus mengaktifkan akses data,

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

Kode:

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

Terima kasih atas informasi yang disediakan semula ... Ya, akhirnya saya tidak harus membuat semua definisi tabel palsu (ketat) ini ketika menggunakan data dari prosedur atau basis data lain yang tersimpan, dan ya Anda dapat menggunakan parameter juga.

Cari tag referensi:

  • SQL 2005 menyimpan prosedur ke dalam tabel temp

  • openquery dengan prosedur tersimpan dan variabel 2005

  • openquery dengan variabel

  • jalankan prosedur tersimpan ke dalam tabel temp

Pembaruan: ini tidak akan berfungsi dengan tabel sementara jadi saya harus menggunakan secara manual membuat tabel sementara.

Pemberitahuan gelandangan : ini tidak akan berfungsi dengan tabel sementara , http://www.sommarskog.se/share_data.html#OPENQUERY

Referensi: Hal berikutnya adalah mendefinisikan LOCALSERVER. Ini mungkin terlihat seperti kata kunci dalam contoh, tetapi sebenarnya hanya nama. Inilah cara Anda melakukannya:

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

Untuk membuat server yang ditautkan, Anda harus memiliki izin ALTER ANY SERVER, atau menjadi anggota dari salah satu peran server tetap sysadmin atau setupadmin.

OPENQUERY membuka koneksi baru ke SQL Server. Ini memiliki beberapa implikasi:

Prosedur yang Anda panggil dengan OPENQUERY tidak dapat merujuk tabel sementara yang dibuat dalam koneksi saat ini.

Koneksi baru memiliki database default sendiri (didefinisikan dengan sp_addlinkedserver, default adalah master), jadi semua spesifikasi objek harus menyertakan nama database.

Jika Anda memiliki transaksi terbuka dan menahan kunci saat Anda menelepon OPENQUERY, prosedur yang dipanggil tidak dapat mengakses apa yang Anda kunci. Artinya, jika Anda tidak hati-hati Anda akan memblokir diri sendiri.

Menghubungkan tidak gratis, jadi ada penalti kinerja.

Doug Lubey dari Louisiana
sumber
1
Jika Anda tidak tahu nama server Anda, gunakan SELECT @@SERVERNAME. Anda juga dapat menggunakanEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Contango
24

Jika Anda cukup beruntung memiliki SQL 2012 atau lebih tinggi, Anda dapat menggunakannya dm_exec_describe_first_result_set_for_object

Saya baru saja mengedit sql yang disediakan oleh gotqn. Terima kasih, terima kasih.

Ini menciptakan tabel temp global dengan nama yang sama dengan nama prosedur. Tabel temp nantinya dapat digunakan sesuai kebutuhan. Hanya saja, jangan lupa untuk menjatuhkannya sebelum menjalankan ulang.

    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
Sandeep Gaadhe
sumber
1
Luar biasa! Hanya satu komentar: gunakan sys.all_objectsalih-alih sys.proceduresjika Anda ingin melakukan ini untuk prosedur tersimpan bawaan.
Gert Arnold
2
Ini juga akan gagal jika SP menggunakan tabel sementara di dalamnya. (Tapi ini cukup praktis untuk memiliki ini sebagai senjata di gudang Anda)
Trubs
23

Proc yang tersimpan ini berfungsi:

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

Ini sedikit pengerjaan ulang ini: Masukkan hasil prosedur tersimpan ke dalam tabel sehingga benar-benar berfungsi.

Jika Anda ingin bekerja dengan tabel sementara maka Anda harus menggunakan ##GLOBALtabel dan menjatuhkannya setelah itu.

satnhak
sumber
17

Untuk memasukkan set rekaman pertama dari prosedur tersimpan ke dalam tabel sementara Anda harus mengetahui yang berikut:

  1. hanya set baris pertama dari prosedur tersimpan yang dapat dimasukkan ke dalam tabel sementara
  2. prosedur tersimpan tidak boleh menjalankan pernyataan T-SQL dinamis ( sp_executesql)
  3. Anda perlu menentukan struktur tabel sementara terlebih dahulu

Di atas mungkin terlihat sebagai batasan, tetapi IMHO itu masuk akal - jika Anda menggunakan sp_executesqlAnda dapat sekali saja mengembalikan dua kolom dan sepuluh, dan jika Anda memiliki beberapa set hasil, Anda tidak dapat memasukkannya ke dalam beberapa tabel juga - Anda dapat memasukkan maksimum dalam dua tabel dalam satu pernyataan T-SQL (menggunakan OUTPUTklausa dan tidak ada pemicu).

Jadi, masalah utamanya adalah bagaimana mendefinisikan struktur tabel sementara sebelum melakukan EXEC ... INTO ...pernyataan.

Yang pertama berfungsi dengan OBJECT_IDsedangkan yang kedua dan ketiga bekerja dengan permintaan Ad-hoc juga. Saya lebih suka menggunakan DMV daripada sp karena Anda dapat menggunakan CROSS APPLYdan membangun definisi tabel sementara untuk beberapa prosedur secara bersamaan.

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;

Juga, perhatikan system_type_namebidang karena ini bisa sangat berguna. Ini menyimpan definisi lengkap kolom. Sebagai contoh:

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

dan Anda dapat menggunakannya secara langsung di sebagian besar kasus untuk membuat definisi tabel.

Jadi, saya pikir dalam sebagian besar kasus (jika prosedur tersimpan sesuai dengan kriteria tertentu), Anda dapat dengan mudah membuat pernyataan dinamis untuk menyelesaikan masalah tersebut (buat tabel sementara, masukkan hasil prosedur tersimpan di dalamnya, lakukan apa yang Anda perlukan dengan data) .


Perhatikan, bahwa objek di atas gagal untuk menentukan data set hasil pertama dalam beberapa kasus seperti ketika pernyataan T-SQL dinamis dieksekusi atau tabel sementara digunakan dalam prosedur tersimpan.

Gotqn
sumber
observasi praktis tentang batasan: jika Anda harus menyisipkan output beberapa sp (sebut saja SP_LEVEL_0) untuk membuat tabel secara dinamis dibuat menggunakan pendekatan di atas dalam sp lain (sebut saja SP_LEVEL_1), Anda tidak dapat melakukan trik yang sama untuk output SP_LEVEL_1 ini untuk beberapa tabel temp lain di SP_LEVEL_2
nahab
17
  1. Saya membuat tabel dengan skema dan data berikut.
  2. Buat prosedur tersimpan.
  3. Sekarang saya tahu apa hasil dari prosedur saya, jadi saya melakukan permintaan berikut.

    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

    NILAI (10, 5, 1, NULL) SET IDENTITY_INSERT [dbo]. [TblTestingTree] Aktif

    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;
Devansh
sumber
15

Jika kueri tidak berisi parameter, gunakan yang OpenQuerylain gunakan OpenRowset.

Hal dasar adalah membuat skema sesuai prosedur yang tersimpan dan memasukkan ke dalam tabel itu. misalnya:

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
Pemecah masalah
sumber
13

Kode

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

Saya harap ini membantu. Harap memenuhi syarat yang sesuai.

SoftwareARM
sumber
11

Saya menemukan Passing Arrays / DataTables ke dalam Stored Procedures yang mungkin memberi Anda ide lain tentang bagaimana Anda bisa menyelesaikan masalah Anda.

Tautan menyarankan untuk menggunakan parameter tipe gambar untuk masuk ke prosedur tersimpan. Kemudian dalam prosedur tersimpan, gambar diubah menjadi tabel variabel yang berisi data asli.

Mungkin ada cara ini bisa digunakan dengan tabel sementara.

kevchadders
sumber
4
Ini tidak lagi diperlukan dalam versi Sql2008 & yang lebih baru dengan diperkenalkannya Parameter Nilai Tabel . Sekarang Anda dapat langsung mengirimkan set data .net atau objek yang dapat datatable ke prosedur tersimpan sql dengan harus melakukan konversi ke byte sebagaimana disebutkan dalam tautan di atas
EndlessSpace
10

Saya menemui masalah yang sama dan inilah yang saya lakukan untuk ini dari saran Paul . Bagian utama di sini adalah untuk digunakan NEWID()untuk menghindari beberapa pengguna menjalankan prosedur toko / skrip pada saat yang sama, rasa sakit untuk tabel sementara global.

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 + ']')
zhongxiao37
sumber
9

Metode lain adalah membuat tipe dan menggunakan PIPELINED untuk kemudian mengirimkan kembali objek Anda. Namun ini terbatas untuk mengetahui kolom. Tetapi ia memiliki keuntungan untuk bisa melakukan:

SELECT * 
FROM TABLE(CAST(f$my_functions('8028767') AS my_tab_type))
pierre
sumber
Apa ini? Tampaknya tidak ada hubungannya dengan SQL Server yang pertanyaan ini tentang
Martin Smith
8

Ini adalah proses 2 langkah sederhana: - membuat tabel sementara - Masukkan ke dalam tabel sementara.

Kode untuk melakukan hal yang sama:

CREATE TABLE #tempTable (Column1 int, Column2 varchar(max));
INSERT INTO #tempTable 
EXEC [app].[Sproc_name]
@param1 = 1,
@param2 =2;
S Krishna
sumber
Diturunkan; sangat mirip dengan jawaban yang ada.
iokevins
6

Setelah mencari di sekitar saya menemukan cara untuk membuat tabel temp secara dinamis untuk setiap prosedur tersimpan tanpa menggunakan OPENROWSETatau OPENQUERYmenggunakan skema umum definisi hasil Stored Procedure terutama ketika Anda bukan Administrator basis data.

Sql server memiliki buit-in proc sp_describe_first_result_setyang dapat memberi Anda skema dari setiap prosedur resultset. Saya membuat tabel skema dari hasil prosedur ini dan secara manual mengatur semua bidang ke 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 

Dikembangkan dan diuji pada versi Sql Server - Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (Build 17134 :)

Anda bisa mengubah skema untuk versi SQL server yang Anda gunakan (jika perlu).

vendettamit
sumber
4

Jika Anda tahu parameter yang dilewati dan jika Anda tidak memiliki akses untuk membuat sp_configure, maka edit prosedur tersimpan dengan parameter ini dan hal yang sama dapat disimpan dalam tabel global ##.

lakshmivisalij
sumber
3

Ini dapat dilakukan dalam SQL Server 2014+ asalkan prosedur tersimpan hanya mengembalikan satu tabel. Jika ada yang menemukan cara melakukan ini untuk beberapa tabel saya ingin tahu tentang hal itu.

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

Ini menarik definisi tabel yang dikembalikan dari tabel sistem, dan menggunakannya untuk membangun tabel temp untuk Anda. Anda kemudian dapat mengisinya dari prosedur tersimpan seperti yang dinyatakan sebelumnya.

Ada juga varian ini yang bekerja dengan Dynamic SQL juga.

Matthew Baker
sumber
2

Beberapa tahun terlambat untuk pertanyaan, tetapi saya membutuhkan sesuatu seperti ini untuk beberapa generasi kode yang cepat dan kotor. Saya percaya karena orang lain telah menyatakan bahwa hanya lebih mudah untuk mendefinisikan tabel temp di muka, tetapi metode ini harus bekerja untuk kueri prosedur tersimpan sederhana atau statemen sql.

Ini akan sedikit berbelit-belit, tetapi meminjam dari kontributor di sini serta solusi Paul White dari DBA Stack Exchange Dapatkan disimpan-hasil jenis kolom prosedur . Sekali lagi, untuk mengulangi pendekatan ini & contoh tidak dirancang untuk proses dalam lingkungan multi-pengguna. Dalam hal ini definisi tabel sedang diatur untuk waktu yang singkat di tabel temp global untuk referensi oleh proses templat pembuatan kode.

Saya belum sepenuhnya menguji ini sehingga mungkin ada peringatan sehingga Anda mungkin ingin pergi ke tautan MSDN dalam jawaban Paul White. Ini berlaku untuk SQL 2012 dan lebih tinggi.

Pertama-tama gunakan prosedur tersimpan sp_describe_first_result_set yang menyerupai uraian Oracle.

Ini akan mengevaluasi baris pertama dari hasil pertama yang ditetapkan sehingga jika prosedur atau pernyataan Anda yang disimpan mengembalikan beberapa kueri, itu hanya akan menggambarkan hasil pertama.

Saya membuat proc tersimpan untuk memecah tugas-tugas yang mengembalikan satu bidang untuk memilih dari untuk membuat definisi tabel temp.

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

Masalahnya adalah Anda perlu menggunakan tabel global, tetapi Anda harus membuatnya cukup unik sehingga Anda bisa sering menjatuhkan dan membuatnya dari sana tanpa khawatir akan tabrakan.
Dalam contoh saya menggunakan Guid (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) untuk variabel global yang mengganti tanda hubung dengan garis bawah

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

Sekali lagi, saya hanya mengujinya dengan kueri prosedur tersimpan sederhana dan kueri sederhana sehingga jarak tempuh Anda dapat bervariasi. Semoga ini bisa membantu seseorang.

Charles Byrne
sumber
1

Yah, Anda harus membuat tabel temp, tetapi tidak harus memiliki skema yang tepat .... Saya telah membuat prosedur tersimpan yang memodifikasi tabel temp yang ada sehingga memiliki kolom yang diperlukan dengan data yang benar ketik dan ketertiban (menjatuhkan semua kolom yang ada, menambahkan kolom baru):

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

Catatan ini tidak akan berfungsi jika sys.dm_exec_describe_first_result_set_for_object tidak dapat menentukan hasil dari prosedur tersimpan (misalnya jika menggunakan tabel temp).

jmoreno
sumber
0

Jika Anda membiarkan SQL dinamis membuat tabel temp, tabel ini dimiliki oleh koneksi SQL Dinamis, sebagai lawan dari koneksi prosedur tersimpan Anda dipanggil dari.

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;

masukkan deskripsi gambar di sini

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, Level 16, Negara 0 Nama objek tidak valid '#Pivoted'. Ini karena #Pivoted dimiliki oleh koneksi SQL Dinamis. Jadi instruksi terakhir

SELECT * FROM #Pivoted

gagal

Salah satu cara untuk tidak menghadapi masalah ini adalah memastikan semua referensi ke #Pivoted dibuat dari dalam kueri dinamis itu sendiri:

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

masukkan deskripsi gambar di sini

Ludovic Aubert
sumber
-5

Saya akan melakukan hal berikut

  1. Buat (konversi SP ke) UDF (Nilai tabel UDF).

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

Hlin
sumber
2
Mungkin ada beberapa kendala untuk membuat langkah pertama Anda. Sebagai contoh jika SP asli menggunakan tabel sementara. UDF tidak dapat menggunakan tabel sementara.
Yucer