Saklı yordamın sonuçlarını geçici bir tabloya ekleme


1578

Nasıl yaparım SELECT * INTO [temp table] FROM [stored procedure]? Tanımlamıyor FROM [Table]ve tanımlamıyor [temp table]musunuz?

SelectBusinessLineiçine tüm veriler tmpBusLineiyi çalışır.

select *
into tmpBusLine
from BusinessLine

Aynı çalışıyorum, ama stored procedureveri döndüren bir kullanmak , tamamen aynı değildir.

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

Çıktı mesajı:

Msg 156, Seviye 15, Durum 1, Satır 2 'exec' anahtar kelimesinin yanında yanlış sözdizimi.

İyi çalışır çıktı saklı yordamıyla aynı yapıya sahip geçici bir tablo oluşturmak için birkaç örnek okudum, ancak herhangi bir sütun sağlamak güzel olurdu.


22
SELECT * INTO [TABLE NAME] ile sütunları, orijinal tablodan kopyalandıkları için bilirsiniz. Saklı bir prosedüre karşı aynı şeyi yapsaydım tam olarak istediğim şey bu.
Ferdeen


7
Sadece "tmpBusLine içine * seçin" kalıcı bir tablo oluşturur işaret etmek istiyorum. Muhtemelen "#tmpBusLine içine * seçin" istersiniz. Orijinal poster bunu zaten öğrendim eminim ama şu anda "geçici tabloya seçin" arama için en iyi sonucu olduğu gibi bu yazı bulmak başkalarına yardımcı olabilir
ktam33

2
Bunun ele alınıp alınmadığını bilmiyorum ama hatayı alma nedeniniz anahtar kelimeden kaynaklanıyor.
Wes Palmer

9
Microsoft'un EXEC'ten SELECT * eklemesi gerekiyor! Lütfen!
kjmerf

Yanıtlar:


704

Bunun için OPENROWSET kullanabilirsiniz . Bir bak. Ayrıca, zaten etkinleştirilmemişse Ad Hoc Dağıtılmış Sorguları etkinleştirmek için sp_configure kodunu ekledim.

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
Bunu yapmanın doğru yolu budur. OPENROWSET, saklı bir yordamın sonuçlarını tablo ifadesi olarak ele almanın tek yoludur.
Rob Farley

37
Bu sadece bir tabloya eklemek biraz hantal görünüyor. Yapmak için bir sürü yapılandırma. Ayrıca denediğimde "Msg 7357, Düzey 16, Durum 2, Satır 1" EXEC GetPartyAnalysisData 146 "nesnesi işlenemiyor. OLE DB sağlayıcısı" SQLNCLI "bağlantılı sunucu için" (null) " sütun yok veya geçerli kullanıcının bu nesne üzerinde izni yok. " Bu yüzden bağlantılı bir sunucu ayarlamanız gerekiyor ...
Ferdeen

10
Bağlantılı bir sunucuya ihtiyacınız yoktur, ancak bağlantı dizesini doğru almanız gerekir ... ve ayrıca veritabanı adı ve sp'nin sahibi de dahil olmak üzere saklı yordamın tam yolunu belirtin.
MartW

18
eeeeew! aynı sunucuya bir başvuru? pis. kesinlikle geçici tablo oluşturmak zorunda daha bir kesmek
Tim Abell

23
Bu bir hack olduğunu ve sırtınızı duvara karşı sürece sürece kaçınılması gerektiğini kabul ediyorum. Sp'nin bir işleve değiştirilmesi muhtemelen daha iyi bir açıdır. BENİM NACİZANE FİKRİME GÖRE.
greg

624

Öncelikle geçici tabloyu bildirmeden yapmak istiyorsanız, saklı yordam yerine kullanıcı tanımlı bir işlev oluşturmayı deneyebilir ve kullanıcı tanımlı işlevin bir tablo döndürmesini sağlayabilirsiniz. Alternatif olarak, saklı yordamı kullanmak istiyorsanız, şöyle bir şey deneyin:

CREATE TABLE #tmpBus
(
   COL1 INT,
   COL2 INT
)

INSERT INTO #tmpBus
Exec SpGetRecords 'Params'

170
Bence amaç şemayı açıkça beyan etmek zorunda kalmadan oluşturmaktı.
Craig

5
Bu ve yukarıdaki @Aaron Alton çözümü arasındaki farkın ne olduğunu bilmek isterim. Bu çok daha basit görünüyor, ama diğer sonuçlardan emin değilim.
funkymushroom

11
Bu işe yarayacak, ancak SpGetRecords saklı yordamına daha fazla sütun eklerseniz, bu patlar.
Brady Holt

15
Her çağrı yığını için yalnızca bir tane EXECT INTO alırsınız. SpGetRecords ve çağırdığı herhangi bir proc bu stratejiyi kendi kodlarında kullanamaz. Bu, SpGetRecords'un koruyucularını şaşırtabilir.
Matt Stephenson

33
Bu soruya hiç cevap vermiyor ve neden bu kadar yükseldiğini anlamıyorum? OP açıkça "[temp tablosu] tanımlanmadan" ifadesini kullandı ve ilk satırınızda geçici tablo oluşturma ifadesi var.
NickG

296

SQL Server 2005'te INSERT INTO ... EXECsaklı yordamın sonucunu bir tabloya eklemek için kullanabilirsiniz . Gönderen MSDN'ın INSERTbelgelerinde (aslında SQL Server 2000,):

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

122
Bu, authors_sales öğesinin önceden tanımlanmasını gerektirir. Bundan kaçınmaya çalışıyorum. Teşekkürler.
Ferdeen

5
Ben de öyle düşündüm. Çok kullanışlı Tmp tablolarına anında ekleme, ancak saklanan bir işlemden döndürülen veri kümesi yapısını bilmeniz gerekiyorsa çok kullanışlı değil. Yardımın için teşekkürler.
Ferdeen


4
Aynı şemayı kullanmak için aşağıdaki gibi bir kopya oluşturabilirsiniz: realTable'dan tempTable'a ilk 0 * 'ı seçin ( stackoverflow.com/a/9206463/73794 )
Hatta Mien

@EvenMien Yorumunuzu gördüğümde anlık olarak heyecanlandım ... ama ne yazık ki bu sadece
procunuzun

193

Bu, sorunuzun biraz değiştirilmiş bir sürümünün cevabıdır. Kullanıcı tanımlı bir işlev için saklı bir yordam kullanımını bırakabilirseniz, satır içi tablo değerli kullanıcı tanımlı bir işlev kullanabilirsiniz. Bu temelde bir tabloyu sonuç kümesi olarak döndüren saklı bir yordamdır (parametreleri alacaktır); ve bu nedenle INTO ifadesiyle güzel bir şekilde yerleştirilecek.

İşte ve kullanıcı tanımlı diğer işlevler hakkında hızlı bir makale . Saklı yordam için hala bir sürüş gereksiniminiz varsa, satır içi tablo değerli kullanıcı tanımlı işlevi saklı yordamla sarabilirsiniz. Saklı yordam, satır içi tablo değerli kullanıcı tanımlı işlevden select * çağırdığında parametreleri geçirir.

Örneğin, belirli bir bölge için müşterilerin listesini almak için satır içi tablo değerli kullanıcı tanımlı bir işleve sahip olursunuz:

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

Daha sonra sonuçlarınızın böyle olmasını sağlamak için bu işlevi çağırabilirsiniz:

SELECT * FROM CustomersbyRegion(1)

Ya da bir seçim yapmak için:

SELECT * INTO CustList FROM CustomersbyRegion(1)

Yine de saklı bir yordama ihtiyacınız varsa, işlevi şu şekilde sarın:

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

Bence bu istenen sonuçları elde etmek için en 'hack-free' yöntemi. Ek komplikasyonlar olmaksızın kullanılması amaçlandığı için mevcut özellikleri kullanır. Satır içi tablo değerli kullanıcı tanımlı işlevi saklı yordamda iç içe geçirerek, işleve iki şekilde erişebilirsiniz. Artı! Gerçek SQL kodu için yalnızca bir bakım noktanız vardır.

OPENROWSET kullanımı önerilmiştir, ancak OPENROWSET işlevinin kullanılması amaçlanmamıştır (Çevrimiçi Kitaplardan):

OLE DB veri kaynağından uzak verilere erişmek için gereken tüm bağlantı bilgilerini içerir. Bu yöntem, bağlantılı bir sunucudaki tablolara erişmeye bir alternatiftir ve OLE DB kullanarak uzak verilere bağlanmak ve bunlara erişmek için tek seferlik, geçici bir yöntemdir. OLE DB veri kaynaklarına daha sık başvurular için, bunun yerine bağlantılı sunucuları kullanın.

OPENROWSET kullanımı işi halledecektir, ancak yerel bağlantıların açılması ve verilerin toplanması için ek yük getirecektir. Ayrıca, her durumda bir seçenek olmayabilir, çünkü bir güvenlik riski oluşturan ve bu nedenle istenmeyebilecek özel bir sorgu izni gerektirir. Ayrıca, OPENROWSET yaklaşımı, birden fazla sonuç kümesi döndüren saklı yordamların kullanılmasını engeller. Birden çok satır içi tablo değeri kullanıcı tanımlı işlevi tek bir saklı yordamda sarmak bunu başarabilir.


4
+1 Tablo değerli bir işlev uygun bir çözümdür. Küçük dezavantajları not etmeliyiz: tablo değerli işlev ekstra bir veritabanı nesnesidir ve buna ayrıcalıklar vermek gerekebilir.
spencer7593

2
Çözümü seviyorum. Vurduğum küçük bir engel, masamın saklı yordamda olabileceği şekilde sipariş verememesi. Peki, ben
hallederim

5
Bir engel daha - "Bir işlev içinden geçici tablolara
erişilemiyor

7
Asıl soru, sp'nin sonuçları ile bir geçici tabloyu nasıl oluşturacağımızdır. Bu iyi bir model, ancak bu soruya
değinmiyor

16
greg, cevabımdaki ilk satırda "Bu, sorunuzun biraz değiştirilmiş bir versiyonunun cevabıdır." Yorumunuz gereksiz.
Christian Loris

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

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

2
"Msg 208, Seviye 16, Durum 1, Satır 1 Geçersiz nesne adı 'tmpBusLine' olsun (muhtemelen önden tanımlanmadığı için).
Ferdeen

1
@Ferds: üzgünüm, ilk isteğinizi anlamadı. Başka bir çözümle güncellendi.
Quassnoi

26
Harika bir çözüm. Bir uyarı, sunucunuzda 'VERİ ERİŞİMİ' ni etkinleştirmeniz gerekir: EXEC sp_serveroption 'TheServerName', 'VERİ ERİŞİMİ', DOĞRU
jcollum

8
Ayrıca sunucuya uzaktan erişime izin vermeniz gerekir. Bunun güvenlik sonuçları olacaktır.
BraveNewMath

7
Hedef saklı yordam geçici tablolar kullanırsa bu çalışmaz
Sal

125

En Kolay Çözüm:

CREATE TABLE #temp (...);

INSERT INTO #temp
EXEC [sproc];

Şemayı bilmiyorsanız, aşağıdakileri yapabilirsiniz. Bu yöntemde ciddi güvenlik riskleri olduğunu lütfen unutmayın.

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

i döndürülen sonuç kümesi sütun bilmiyorsanız o zaman ??? yani sütun değişebilir. sonuç geçici tabloya nasıl eklenir ???
SHEKHAR SHETE

OPENQUERY kullanabilirsiniz, ancak güvenlik açıklarıyla birlikte gelmesi önerilmez.
Tigerjz32

1
"Eğer o zaman döndürülen sonuç kümesi sütununu bilmiyorsanız" o zaman mantık içinde kullanamazsınız. Ne olduğunu bilmiyorsanız verileri nasıl kullanacaksınız?
Adriaan Davel

@AdriaanDavel Verilerinizi her zaman bilmeniz gerektiğine katılıyorum (en iyi uygulama), ancak söylediği şey, sproc'un dinamik sütunları döndürdüğü ve şemanın nasıl görüneceğini her zaman bilmediğinizdir. Bu durumda, anında bir tablo eklemek ve oluşturmak için OPENROWSET'i kullanabilirsiniz. Ancak, bunu yaparken bariz güvenlik riskleri vardır ...
Tigerjz32

1
@nurettin bazen saklı yordamın ne döneceğini bilmiyorsunuz. Bu durumda ne olur? Geçici tabloyu (saklı yordamın ne döndüreceğini bilmediğinizde) nasıl oluşturabilir ve saklı yordamdan tabloya nasıl ekleyebilirsiniz?
Tigerjz32

106

Saklı yordam çok sütun döndürdüğünde ve sonucu tutmak için el ile geçici bir tablo oluşturmak istemiyorsanız, en kolay yol saklı yordama gitmek ve bir "içine" yan tümcesi eklemek olduğunu buldum son select deyimi ve where yan tümcesine 1 = 0 ekleyin.

Saklı yordamı bir kez çalıştırın ve geri dönüp eklediğiniz SQL kodunu kaldırın. Şimdi, saklı yordamın sonucuyla eşleşen boş bir tablonuz olacak. Geçici bir tablo için "tablo olarak oluştur" komut dosyası veya doğrudan bu tabloya ekleyebilirsiniz.


9
+1, mükemmel öneri. @TableCreate adlı sproc'a veya isteğe bağlı olmadığında yukarıdaki adımları uygulayan benzer bir şeye hızlı bir isteğe bağlı değişken bile ekleyebilirsiniz. Bir kez kurulduktan sonra sproc'un değiştirilmesini gerektirmez.
Ian Roke

1
@dotjoe SELECT INTOGeçici bir tablo yapar ve geçici tablodan bir komut dosyası oluşturur musunuz? Temp tabloları görünür tempdbama sağ tıklama ve oluşturma komut dosyası yapamıyorum. Herhangi bir yardım takdir.
DotnetDude

2
@DotNetDude select ... into new_tableörtük olarak gerçek bir tablo oluşturabilirsiniz.
dotjoe

Sonra boş tablo şemasından kaba sütun tanımını alın; sonunda '...' yerine TABLE_NAME yasal 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
adını girin

Bu en iyi çözüm!
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
OP orijinal sorusunu ele almaz, önce geçici tabloyu tanımlamaksızın eki yapar.
t.durden

48

Saklı yordam yalnızca verileri alıyor mu veya değiştiriyor mu? Yalnızca almak için kullanılıyorsa, saklı yordamı bir işleve dönüştürebilir ve aşağıdaki gibi bildirmek zorunda kalmadan Ortak Tablo İfadelerini (CTE'ler) kullanabilirsiniz:

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

Bununla birlikte, CTE'den alınması gereken her şey sadece bir ifadede kullanılmalıdır. Yapamaz with temp as ...ve birkaç satır SQL'den sonra kullanmaya çalışamazsınız . Daha karmaşık sorgular için bir deyimde birden çok CTE'niz olabilir.

Örneğin,

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
Bunlar geçici tablolar değil, CTE'ler. technet.microsoft.com/en-us/library/...
YÜCER

5
Thanks @yucer ... O zamanlar CTE'ler olarak adlandırıldıklarını bilmiyordum inanıyorum :)
SO Kullanıcı

48

Saklanan proc sonuç tablosu "tablo oluştur" deyimini elle yazmak için çok karmaşıksa ve OPENQUERY VEYA OPENROWSET kullanamazsanız, sizin için sütun ve veri türleri listesini oluşturmak için sp_help kullanabilirsiniz. Sütun listesine sahip olduktan sonra, bu sadece ihtiyaçlarınıza göre biçimlendirme meselesidir.

Adım 1: Çıkış sorgusuna "#temp içine" ekleyin (örneğin, [...] 'den #temp içine "[[]] seçin").

En kolay yol, çıkış sorgusunu doğrudan proc'ta düzenlemektir. depolanan işlemi değiştiremezseniz, içeriği yeni bir sorgu penceresine kopyalayabilir ve sorguyu orada değiştirebilirsiniz.

Adım 2: Temp tablosunda sp_help komutunu çalıştırın. (örn. "exec tempdb..sp_help #temp")

Temp tablosunu oluşturduktan sonra, varchar alanlarının boyutu da dahil olmak üzere sütunların ve veri türlerinin bir listesini almak için temp tablosunda sp_help komutunu çalıştırın.

3. Adım: Veri sütunlarını ve türlerini tablo oluştur ifadesine kopyalama

Sp_help çıktısını bir "tablo oluştur" deyimine biçimlendirmek için kullandığım bir Excel sayfası var. Süslü bir şeye ihtiyacınız yok, sadece kopyalayıp SQL editörünüze yapıştırın. Saklı yordamın sonuçlarını eklemek için kullanabileceğiniz bir "Tablo #x [...]" veya "declare @x table [...]" ifadesi oluşturmak için sütun adlarını, boyutlarını ve türlerini kullanın.

4. Adım: Yeni oluşturulan tabloya ekleyin

Şimdi bu iş parçacığında açıklanan diğer çözümlere benzeyen bir sorguya sahip olacaksınız.

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

INSERT INTO @t 
Exec spMyProc 

Bu teknik, bir temp tablosunu ( #temp) bir tablo değişkenine ( @temp) dönüştürmek için de kullanılabilir . Bu, create tableifadeyi kendiniz yazmaktan daha fazla adım olsa da , büyük süreçlerde yazım hataları ve veri türü uyuşmazlıkları gibi manuel hataları önler. Yazım hatalarını ayıklamak, ilk etapta sorguyu yazmaktan daha uzun sürebilir.


37

OPENROWSET size sorun çıkarıyorsa, 2012'den itibaren başka bir yol var; burada belirtildiği gibi sys.dm_exec_describe_first_result_set_for_object özelliğini kullanın: Saklı yordamın sütun adlarını ve türlerini al?

İlk olarak, geçici tablo için SQL oluşturmak üzere bu saklı yordamı oluşturun:

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

Prosedürü kullanmak için aşağıdaki şekilde arayın:

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

Genel bir geçici tablo kullandığımı unutmayın. Bunun nedeni, dinamik SQL'i çalıştırmak için EXEC kullanmak kendi oturumunu oluşturmasıdır, bu nedenle sıradan bir geçici tablo sonraki kodların kapsamı dışında kalır. Küresel bir geçici tablo bir sorun varsa, olabilir sıradan bir geçici tablo kullanmak, ancak sonraki herhangi bir SQL, ayrıca EXEC deyimi tarafından yürütüldüğünde dinamik, olması gerekir.


4
Tabloyu oluşturmayı unuttunuz @SQL.
Trisped

32

Quassnoi beni en çok oraya koydu, ama bir şey eksikti:

**** Saklı yordamda parametreleri kullanmam gerekiyordu.

Ve OPENQUERY bunun olmasına izin vermez:

Bu yüzden sistemi çalıştırmanın bir yolunu buldum ve aynı zamanda tablo tanımını bu kadar katı hale getirmem ve başka bir saklı yordam içinde yeniden tanımlamam gerekmiyor (ve elbette kırılma şansını yakalayın)!

Evet, sahte yordamlarla OPENQUERY deyimini kullanarak saklı yordamdan döndürülen tablo tanımını dinamik olarak oluşturabilirsiniz ( SONUÇ NOKTASI AYARI , aynı sayıda alanı döndürdüğü ve iyi verilere sahip bir veri kümesiyle aynı konumda).

Tablo oluşturulduktan sonra, tüm gün boyunca geçici tabloya exec saklı yordamı kullanabilirsiniz.


Ve (yukarıda belirtildiği gibi) veri erişimini etkinleştirmeniz gerektiğini,

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

Kod:

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

Orijinal olarak sağlanan bilgi için teşekkürler ... Evet, nihayet başka bir saklı yordam veya veritabanından veri kullanırken tüm bu sahte (katı) tablo tanımları oluşturmak zorunda değilsiniz , ve evet de parametreleri kullanabilirsiniz.

Arama referans etiketleri:

  • SQL 2005 saklı yordam geçici tabloya

  • saklı yordam ve değişkenlerle açık sorgu 2005

  • değişkenli openquery

  • saklı yordamı geçici tabloya yürüt

Güncelleme: Bu geçici tablolar ile çalışmaz, bu yüzden manuel olarak geçici tablo oluşturmak için başvurmak zorunda kaldı.

Bummer uyarısı : Bu geçici tablolarla çalışmaz , http://www.sommarskog.se/share_data.html#OPENQUERY

Referans: Bir sonraki şey LOCALSERVER tanımlamaktır. Örnekte bir anahtar kelime gibi görünebilir, ancak aslında sadece bir isimdir. Bunu şu şekilde yapabilirsiniz:

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

Bağlantılı bir sunucu oluşturmak için ALTER ANY SERVER iznine sahip olmanız veya sysadmin veya setupadmin sabit sunucu rollerinden herhangi birinin üyesi olmanız gerekir.

OPENQUERY, SQL Server'a yeni bir bağlantı açar. Bunun bazı sonuçları vardır:

OPENQUERY ile çağırdığınız yordam, geçerli bağlantıda oluşturulan geçici tablolara başvuramaz.

Yeni bağlantının kendi varsayılan veritabanı vardır (sp_addlinkedserver ile tanımlanır, varsayılan master'dır), bu nedenle tüm nesne belirtimleri bir veritabanı adı içermelidir.

Açık bir işleminiz varsa ve OPENQUERY'yi aradığınızda kilitleri tutuyorsanız, çağrılan prosedür kilitlediğiniz şeye erişemez. Yani, dikkatli olmazsanız kendinizi bloke edersiniz.

Bağlanmak ücretsiz değildir, bu nedenle bir performans cezası vardır.


1
Sunucu adınızı bilmiyorsanız, tuşunu kullanın SELECT @@SERVERNAME. Ayrıca kullanabilirsinizEXEC sp_serveroption @@SERVERNAME, 'DATA ACCESS', TRUE
Contango

24

SQL 2012 veya daha yüksek bir sürüme sahip olacak kadar şanslıysanız, dm_exec_describe_first_result_set_for_object

Ben gotqn tarafından sağlanan sql düzenledim. Teşekkürler gotqn.

Bu, yordam adıyla aynı adlı bir genel geçici tablo oluşturur. Geçici tablo daha sonra gerektiği gibi kullanılabilir. Yeniden çalıştırmadan önce bırakmayı unutmayın.

    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
Mükemmel! Sadece bir açıklama: yerleşik saklı yordamlar için bunu yapmak sys.all_objectsyerine kullanın sys.procedures.
Gert Arnold

2
Bu, SP içinde geçici tablolar kullanıyorsa da başarısız olur. (ancak bunu cephaneliğinizde bir proc olarak kullanmak oldukça kullanışlı)
Trubs

23

Bu saklı süreç işi yapar:

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

Bunun hafif bir yeniden çalışması: Saklı yordam sonuçlarını gerçekten işe yarayacak şekilde tabloya ekleyin .

Geçici bir tabloyla çalışmasını istiyorsanız, bir ##GLOBALtablo kullanmanız ve daha sonra bırakmanız gerekir.


17

Saklı yordamın ilk kayıt kümesini geçici bir tabloya eklemek için aşağıdakileri bilmeniz gerekir:

  1. saklı yordamın yalnızca ilk satır kümesi geçici bir tabloya eklenebilir
  2. saklı yordam dinamik T-SQL deyimi ( sp_executesql) yürütmemelidir
  3. önce geçici tablonun yapısını tanımlamanız gerekir

Yukarıdaki sınırlama olarak görünebilir, ancak IMHO mükemmel bir anlam ifade eder - kullanıyorsanız sp_executesql, bir kez iki sütun ve on kez geri dönebilirsiniz ve birden fazla sonuç kümeniz varsa, bunları birkaç tabloya da ekleyemezsiniz - maksimum bir T-SQL deyiminde iki tabloda ( OUTPUTyan tümce ve hiçbir tetikleyici kullanarak ).

Yani, esas olarak EXEC ... INTO ...ifadeyi gerçekleştirmeden önce geçici tablo yapısının nasıl tanımlanacağı .

Birincisi OBJECT_ID, ikincisi ve üçüncüsü Geçici sorgularla çalışır. CROSS APPLYAynı anda birden çok yordam için geçici tablo tanımlarını kullanabileceğiniz ve oluşturabileceğiniz için sp yerine DMV'yi kullanmayı tercih ederim .

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;

Ayrıca, system_type_nameçok yararlı olabileceğinden alana dikkat edin . Sütun tam tanımını saklar. Örneğin:

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

ve tablo tanımını oluşturmak için çoğu durumda doğrudan kullanabilirsiniz.

Bu nedenle, çoğu durumda (saklı yordam belirli ölçütlerle eşleşiyorsa) bu tür sorunları çözmek için kolayca dinamik ifadeler oluşturabilirsiniz (geçici tablo oluşturun, saklı yordam sonucunu ekleyin, verilerle ihtiyacınız olanı yapın) .


Yukarıdaki nesnelerin , dinamik T-SQL ifadeleri yürütüldüğünde veya saklı yordamda geçici tablolar kullanıldığında olduğu gibi bazı durumlarda ilk sonuç kümesi verilerini tanımlayamadığını unutmayın .


sınırlamalarla ilgili pratik gözlem: başka bir sp'de yukarıdaki yaklaşım kullanılarak dinamik olarak oluşturulan geçici tabloya bazı sp (SP_LEVEL_0 diyelim) çıkışını eklemeniz gerekiyorsa (SP_LEVEL_1 diyelim), bu SP_LEVEL_1 SP_LEVEL_2'de başka bir sıcaklık tablosu
nahab

17
  1. Aşağıdaki şema ve verileri içeren bir tablo oluşturuyorum.
  2. Saklı yordam oluşturun.
  3. Şimdi prosedürümün sonucunun ne olduğunu biliyorum, bu yüzden aşağıdaki sorguyu gerçekleştiriyorum.

    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

    DEĞERLER (10, 5, 1, NULL) SETENTENT_INSERT [dbo]. [TblTestingTree] Açık

    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

Sorgu parametre içermiyorsa, use use OpenQuerykomutunu kullanın OpenRowset.

Temel şey, saklı yordama göre şema oluşturmak ve bu tabloya eklemek olacaktır. Örneğin:

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

kod

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

Umarım bu yardımcı olur. Lütfen uygun şekilde nitelendirin.


11

Ben bulundu procedure içine Diziler / datatables geçme size problem çözme nasıl gidebileceğimi başka fikir verebilir.

Bağlantı , saklı yordama geçmek için bir Görüntü türü parametresi kullanmanızı önerir . Daha sonra saklı yordamda, görüntü orijinal verileri içeren bir tablo değişkenine dönüştürülür.

Belki de bunun geçici bir tabloyla kullanılabilmesinin bir yolu vardır.


4
Bu, Sql2008 ve sonraki sürümlerde Tablo Değer Parametrelerinin tanıtılmasıyla artık gerekli değildir . Şimdi yukarıdaki bağlantıda belirtildiği gibi bayta dönüştürme yapmak zorunda kalan bir .net veri kümesini veya datatable nesnesini bir sql saklı yordamına doğrudan geçirebilirsiniz
EndlessSpace

10

Aynı problemle tanıştım ve işte Paul'un önerisinden bunun için yaptım . Ana bölüm, NEWID()birden fazla kullanıcının aynı anda mağaza prosedürlerini / komut dosyalarını çalıştırmasını önlemek için kullanmaktır , küresel geçici tablo için acı.

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

Başka bir yöntem bir tür oluşturmak ve daha sonra nesnenizi geri geçirmek için PIPELINED kullanmaktır. Ancak bu sütunları bilmekle sınırlıdır. Ancak bunu yapabilme avantajına sahiptir:

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

Bu nedir? Bu soru hakkında SQL Server ile ilgisi yok gibi görünüyor
Martin Smith

8

Bu 2 adımlı basit bir işlemdir: - geçici tablo oluşturma - Geçici tabloya ekleme.

Aynı işlemi gerçekleştirmek için kod:

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

downvoted; mevcut cevaplara çok benzer.
iokevins

6

Etrafa baktıktan sonra , saklı yordamın sonuç tanımının genel şemasını kullanmadan OPENROWSETveya OPENQUERYkullanmadan, özellikle veritabanı yöneticisi olmadığınızda , geçici olarak geçici bir tablo oluşturmak için bir yol buldum .

Sql sunucusu herhangi bir yordam sp_describe_first_result_setsonuç kümesinin şemasını sağlayabilir bir buit-in proc vardır. Bu yordamın sonuçlarından bir şema tablosu oluşturdum ve tüm alanı el ile NULLABLE olarak ayarladım.

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 

Sql Server sürümünde geliştirildi ve test edildi - Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (Derleme 17134 :)

Kullandığınız SQL sunucusu sürümünüz için şemayı düzenleyebilirsiniz (gerekirse).


4

Geçirilen parametreleri biliyorsanız ve sp_configure yapmak için erişiminiz yoksa, saklı yordamı bu parametrelerle düzenleyin ve aynı ## global tablosunda saklanabilir.


3

Saklı yordamın yalnızca bir tablo döndürmesi koşuluyla bu SQL Server 2014+ ile yapılabilir. Herkes bunu birden çok tablo için yapmanın bir yolunu bulursa ben bunu bilmek isterim.

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

Bu, döndürülen tablonun tanımını sistem tablolarından alır ve geçici tabloyu sizin için oluşturmak için kullanır. Daha sonra, daha önce belirtildiği gibi saklı yordamdan doldurabilirsiniz.

Bunun da Dinamik SQL ile çalışan varyantları vardır.


2

Soruya birkaç yıl geç kaldı, ancak bazı hızlı ve kirli kod üretimi için böyle bir şeye ihtiyacım vardı. Diğerlerinin belirttiği gibi, geçici tabloyu önceden tanımlamanın daha kolay olduğuna inanıyorum, ancak bu yöntem basit saklı yordam sorguları veya sql ifadeleri için çalışmalıdır.

Bu biraz kıvrımlı olacak, ancak burada katkıda bulunanlardan ve Paul White'ın DBA Stack Exchange'den çözümü Saklı yordam sonucu sütun türlerini alıyor . Yine, bu yaklaşımı tekrarlamak ve örnek çok kullanıcılı bir ortamdaki işlemler için tasarlanmamıştır. Bu durumda, tablo tanımı, bir kod oluşturma şablonu işlemi tarafından referans olarak bir genel geçici tabloda kısa bir süre için ayarlanmaktadır.

Paul White'ın cevabındaki MSDN bağlantısına gitmek isteyebileceğinizden uyarılar olabileceğinden bunu tamamen test etmedim. Bu, SQL 2012 ve sonraki sürümler için geçerlidir.

Öncelikle Oracle'ın açıklamasına benzeyen saklı yordamı sp_describe_first_result_set kullanın .

Bu, ilk sonuç kümesinin ilk satırını değerlendirir, böylece saklı yordamınız veya deyiminiz birden çok sorgu döndürürse, yalnızca ilk sonucu açıklar.

Geçici tablo tanımı oluşturmak için seçim için tek bir alan döndüren görevleri yıkmak için bir saklı proc oluşturdum.

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

Bilmeniz, küresel bir masa kullanmanız gerektiğidir, ancak bir çarpışmadan endişe etmeden sık sık düşüp yaratabileceğiniz kadar benzersiz hale getirmeniz gerekir.
Örnekte, genel değişken için kısa çizgileri alt çizgi ile değiştiren bir Kılavuz (FE264BF5_9C32_438F_8462_8A5DC8DEE49E) kullandım

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

Yine, sadece basit saklı yordam sorguları ve basit sorgularla test ettim, böylece kilometre değişebilir. Umarım bu birine yardımcı olur.


1

Peki, bir geçici tablo oluşturmak zorunda, ancak doğru şemasına sahip olmak zorunda değilsiniz .... Ben doğru bir veri ile gerekli sütunları olacak şekilde varolan bir geçici tabloyu değiştiren bir saklı yordam oluşturdum türü ve sırası (mevcut tüm sütunları bırakarak, yeni sütunlar ekleyerek):

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

Sys.dm_exec_describe_first_result_set_for_object saklanan yordamın sonuçlarını belirleyemezse (örneğin geçici tablo kullanıyorsa) bunun işe yaramayacağını unutmayın .


0

Dinamik SQL'in geçici tablo oluşturmasına izin verirseniz, bu tablo, saklı yordamınızın çağrıldığı bağlantının aksine Dinamik SQL bağlantısına aittir.

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;

resim açıklamasını buraya girin

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, Seviye 16, Durum 0 Geçersiz nesne adı '#Pivoted'. Bunun nedeni, #Pivoted'un Dinamik SQL bağlantısına ait olmasıdır. Yani son talimat

SELECT * FROM #Pivoted

başarısız olur.

Bu sorunla yüzleşmemenin bir yolu, #Pivoted'a yapılan tüm referansların dinamik sorgunun içinden yapıldığından emin olmaktır:

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

resim açıklamasını buraya girin


-5

Aşağıdakileri yapardım

  1. Bir UDF (Tablo değeri UDF) oluşturun (SP'yi dönüştürün).

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


2
İlk adımınızı atmanız için bazı engeller olabilir. Örneğin, orijinal SP geçici tablolar kullanıyorsa. UDF'ler geçici tablo kullanamaz.
yucer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.