วิธีที่ง่ายที่สุดในการสร้างตารางชั่วคราวใน SQL Server ที่สามารถเก็บผลลัพธ์ของกระบวนงานที่เก็บไว้คืออะไร


50

หลายครั้งที่ฉันต้องเขียนสิ่งต่อไปนี้เมื่อต้องจัดการกับ SQL Server

create table #table_name
(
    column1 int,
    column2 varchar(200)
    ...
)

insert into #table_name
execute some_stored_procedure;

แต่สร้างตารางที่มีไวยากรณ์ที่แน่นอนเนื่องจากผลลัพธ์ของกระบวนงานที่เก็บไว้เป็นงานที่น่าเบื่อ ตัวอย่างเช่นผลลัพธ์ของsp_helppublicationมี 48 คอลัมน์! ฉันต้องการทราบว่ามีวิธีง่ายๆในการทำเช่นนี้หรือไม่

ขอบคุณ


หากคุณต้องการรูปแบบเอาต์พุตที่กำหนด (และหากคุณเป็น DBA คุณควรเลือกรูปแบบที่กำหนด!) พิจารณา UDF ที่มีค่าเป็นตาราง น่าเสียดายที่พวกเขามีข้อ จำกัด ที่ร้ายแรงดังนั้นจึงไม่ใช่ตัวเลือกเสมอไป
Jon of All Trades

คำตอบ:


36

หากโพรซีเดอร์ส่งคืนชุดผลลัพธ์เพียงชุดเดียวและเปิดใช้งานตัวเลือกคิวรีแบบกระจายเฉพาะกิจ

SELECT * 
INTO #T 
FROM OPENROWSET('SQLNCLI', 
                'Server=(local)\MSSQL2008;Trusted_Connection=yes;',
                 'SET FMTONLY OFF;EXEC sp_who')

หรือคุณสามารถตั้งค่าเซิร์ฟเวอร์ที่เชื่อมโยงลูปแบ็คและใช้แทน

EXEC sp_addlinkedserver @server = 'LOCALSERVER',  @srvproduct = '',
                        @provider = 'SQLNCLI', @datasrc = @@servername

SELECT *
INTO  #T
FROM OPENQUERY(LOCALSERVER, 
               'SET FMTONLY OFF;
               EXEC sp_who')

คุณไม่หมายถึงSET FMT_ONLY ONเหรอ
Andreas Ågren

@ Andreas - ไม่เพราะฉันคิดว่าเป็นความคิดที่จะสร้างและเติมตารางจากการส่งออกขั้นตอนการจัดเก็บ
Martin Smith

18

ใน SQL Server 2012 ขึ้นไปคุณสามารถใช้แบบsys.dm_exec_describe_first_result_setโลคัลโดยสมมติว่าชุดผลลัพธ์ที่คุณอยู่หลังเป็นผลลัพธ์แรก :

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += ',' + CHAR(13) + CHAR(10) + CHAR(9)
    + name + ' ' + system_type_name
    FROM sys.dm_exec_describe_first_result_set('sp_who', NULL, 1);

SELECT @sql = N'CREATE TABLE #f
(' + STUFF(@sql, 1, 1, N'') + '
);';

PRINT @sql;

ผลลัพธ์:

CREATE TABLE #f
(
    spid smallint,
    ecid smallint,
    status nchar(30),
    loginame nvarchar(128),
    hostname nchar(128),
    blk char(5),
    dbname nvarchar(128),
    cmd nchar(16),
    request_id int
);

โปรดทราบว่ามีข้อ จำกัด : หากกระบวนงานที่เก็บไว้ของคุณสร้างตาราง #temp ฟังก์ชันเมทาดาทาจะไม่ทำงาน นี่คือเหตุผลที่ฉันไม่ได้ใช้ sp_who2 :-)


มีการSELECT @sql += *expression*บันทึกไวยากรณ์ไว้ที่ใดที่หนึ่งหรือไม่ ควรORDER BYรวมไว้เพื่อทำให้มีเสถียรภาพหรือไม่
Ross Presser

1
@Ross ใช่มันถูกนำมาใช้ใน SQL Server 2008 และเป็นเอกสารที่นี่ ORDER BYเป็นที่รู้จักกันจริงจะทำให้เรื่องนี้น้อยมีเสถียรภาพ หากคุณต้องการผลในลำดับที่คาดเดาได้ใช้FOR XML PATHหรือหากในรุ่นใหม่พอของ SQL STRING_AGGServer,
Aaron Bertrand

1
การแก้ไขเล็กน้อย: คุณเชื่อมโยงคณิตศาสตร์+=... สตริง+=เป็นเอกสารที่นี่ แต่ขอบคุณ!
Ross Presser

@Ross yup ขอโทษ
Aaron Bertrand

3

ไม่ผลลัพธ์ของกระบวนงานที่เก็บไว้อาจแตกต่างกันอย่างมาก: ไม่ได้ออกแบบมาเพื่อส่งคืนชุดผลลัพธ์หนึ่งชุดเหมือนกับ SELECT บนบางวัตถุเสมอ

คุณต้องดำเนินการสร้างตาราง


1

ฉันจะเขียนขั้นตอนเพื่อสร้างตารางสำหรับฉัน:

CREATE PROCEDURE [dbo].[p_create_table_from_procedure]
    @TABLE_NAME AS NVARCHAR(MAX),
    @PROCEDURE_NAME AS NVARCHAR(MAX)

As
    DECLARE @CREATE_TABLE_QUERY NVARCHAR(MAX) = N'';


    SELECT 
        @CREATE_TABLE_QUERY += ', ' + name + ' ' + UPPER(system_type_name) + CHAR(13) + CHAR(10) + CHAR(9)

    FROM 
        sys.dm_exec_describe_first_result_set(@procedure_name, NULL, 1);


    SELECT 
        @CREATE_TABLE_QUERY = N'CREATE TABLE ' + @table_name + '(' + CHAR(13) + CHAR(10) + CHAR(9) + STUFF(@CREATE_TABLE_QUERY, 1, 1, N'') + ');';

    PRINT @CREATE_TABLE_QUERY;

จากนั้นโทรหาด้วย:

EXEC p_create_table_from_procedure 'YOUR_TABLE_NAME_HERE', 'YOUR_PROCEDURE_NAME_HERE'

หมายเหตุ : แทนที่ 'YOUR_PROCEDURE_NAME_HERE' ด้วยชื่อของขั้นตอนการจัดเก็บของคุณเอง

หมายเหตุ : แทนที่ YOUR_TABLE_NAME_HERE ด้วยชื่อตารางที่คุณเลือก

ด้านบนจะสร้างสิ่งนี้:

CREATE TABLE YOUR_TABLE_NAME_HERE(
     WeekName VARCHAR(40)
    , Line Name VARCHAR(50)
    , TheDate DATETIME
    , ReceivedAll INT
    , Answered INT
    , Abandoned INT
    , Call Length INT
    , WaitTimeAnswer INT
    , WaitTimeAbandon INT
    , PeriodName VARCHAR(10)
    , Week SMALLINT
    , Period SMALLINT
    , Year SMALLINT
    , WeekInPeriod SMALLINT
    , NumWeeksInPeriod SMALLINT
    , WeekendDate DATETIME
    , CRCOperative VARCHAR(100)
    , CallType VARCHAR(20)
    , Charge Time INT
    , SourceNumber VARCHAR(80)
    , DestinationNumber VARCHAR(80)
    , CallStart DATETIME
    , Out of Hours VARCHAR(12)
    , IsWorkingDay BIT
    );

สิ่งนี้แตกต่างจากคำตอบของ @ AaronBertrand ด้านบนอย่างไร
Max Vernon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.