none
הכנסת OUTPUT של SP לטבלה זמנית מבלי להגדיר את מבנה הטבלה RRS feed

  • שאלה

  • שלום רב,

    אני מעוניין להשתמש ב

    INSERT INTO #TMP EXEC SP_MYSP מתוך SP ראשי.

    השימוש מחייב אותי להגדיר מראש את מבנה הטבלה ע"י CREATE TABLE כך שאם מישהו ישנה את SP_MYSP הפרוצדורה הראשית תתרסק.
    האם יש פתרון דומה ל SELECT INTO עבור SP כך שלא תהיה בעיה אם יוסיפו מאוחר יותר שדות נוספים ל OUTPUT של SP_MYSP?

    יום שלישי 11 נובמבר 2014 08:33

תשובות

  • כמוב שיש פתרון, יש תמיד תרון ויש תמיד דרך להגיע לכל מה שצריכים. כל מה שצריך זה לדעת מה הפתרון ולא האם יש פםתרון :-)

    לעצם הצורך שלך, הפתרון פשוט: לא לעשות שמוש ב INSERT INTO שנועד במיוחד כדי ליצור טבלה חדשה. במקום זה אתה יכול לעבוד עם

    INSERT <table name> (<columns list>) 

    SELECT ....


    signature   Ronen Ariely
     [Personal Site]    [Blog]    [Facebook]

    • הוצע כתשובה על-ידי Eran Sharvit יום שלישי 11 נובמבר 2014 12:13
    • סומן כתשובה על-ידי Eran Sharvit יום שישי 21 נובמבר 2014 11:48
    יום שלישי 11 נובמבר 2014 10:39
    מנחה דיון
  • הי,

    יש שלושה פתרונות אפשריים למה שאתה צריך.

    הפתרון הראשון עושה שימוש ב-OPENQUERY. הוא ניגש דרך Linked Server לאותו Instance ומריץ את ה-Stored Procedure, אבל אז אתה יכול להשתמש ב-SELECT INTO. אתה צריך לפני זה לאפשר גישה דרך Linked Server לאותו שרת. החיסרון של הפתרון הזה הוא שאתה פותח Connection נוסף לאותו שרת.

    -- Solution #1
    
    USE
    	master;
    GO
    
    
    EXECUTE sys.sp_serveroption
    	@server		= N'YourInstanceName' ,
    	@optname	= 'data access' ,
    	@optvalue	= 'TRUE';
    GO
    
    
    SELECT
    	*
    INTO
    	#ResultsTable
    FROM
    	OPENQUERY ([YourInstanceName] , N'EXECUTE YourDatabaseName.YourSchemaName.YourStoredProcedureName');
    GO
    

    הפתרון השני הוא דומה, אך הוא משתמש ב-OPENROWSET במקום ב-OPENQUERY, ואז אתה לא צריך להשתמש ב-Linked Server, ולא צריך לקנפג את ה-Instance לאפשר גישה דרך Linked Server, כמו שעשינו קודם. מצד שני, אתה צריך לאפשר את "Ad Hoc Distributed Queries". גם כאן, אתה פותח Connection נוסף לאותו שרת.

    -- Solution #2
    
    USE
    	master;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'show advanced options' ,
    	@configvalue	= 1;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'Ad Hoc Distributed Queries' ,
    	@configvalue	= 1;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'show advanced options' ,
    	@configvalue	= 0;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    SELECT
    	*
    INTO
    	#ResultsTable
    FROM
    	OPENROWSET (N'SQLNCLI' , N'Server=YourInstanceName;Trusted_Connection=yes;' , N'EXECUTE YourDatabaseName.YourSchemaName.YourStoredProcedureName');
    GO
    

    הפתרון השלישי משתמש ב-sys.dm_exec_describe_first_result_set_for_object. כאן הרעיון הוא לבנות את הטבלה הזמנית באופן דינמי. במקרה הזה אתה חוסך את ה-Connection הנוסף וגם לא מתערב בשום הגדרה של השרת. אבל הפתרון יותר מסורבל, והבעיה העיקרית היא שהטבלה הזמנית לא מוכרת בקוד החיצוני אלא רק בתוך הקוד הדינמי, ולכן אתה צריך להמשיך לכתוב את הקוד שלך בתוך הקוד הדינמי על מנת שתוכל לגשת לטבלה.

    -- Solution #3
    
    USE
    	YourDatabaseName;
    GO
    
    
    DECLARE
    	@Command AS NVARCHAR(MAX);
    
    SET @Command =
    	N'
    		CREATE TABLE
    			#ResultsTable
    		(
    			';
    
    SELECT
    	@Command +=
    		name + N' ' + UPPER (system_type_name) + N' ' +
    			CASE
    				is_nullable
    			WHEN 0
    				THEN N'NOT NULL'
    			WHEN 1
    				THEN N'NULL'
    			END +
    		N' ,
    			'
    FROM
    	sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID (N'YourSchemaName.YourStoredProcedureName') , 0)
    WHERE
    	is_hidden = 0
    ORDER BY
    	column_ordinal ASC;
    
    SET @Command = LEFT (@Command , LEN (@Command) - 7);
    
    SET @Command +=
    	N'
    		);
    
    		INSERT INTO
    			#ResultsTable
    		EXECUTE YourSchemaName.YourStoredProcedureName;
    	';
    
    EXECUTE sys.sp_executesql
    	@statement = @Command;
    GO
    

    בהצלחה!

    -----------------------------
    גיא גלנצר
    יועץ ומדריך SQL Server
    Madeira - SQL Server Services
    http://www.madeirasql.com

    • סומן כתשובה על-ידי Eran Sharvit יום שישי 21 נובמבר 2014 11:49
    יום שישי 14 נובמבר 2014 02:49
    מנחה דיון

כל התגובות

  • כמוב שיש פתרון, יש תמיד תרון ויש תמיד דרך להגיע לכל מה שצריכים. כל מה שצריך זה לדעת מה הפתרון ולא האם יש פםתרון :-)

    לעצם הצורך שלך, הפתרון פשוט: לא לעשות שמוש ב INSERT INTO שנועד במיוחד כדי ליצור טבלה חדשה. במקום זה אתה יכול לעבוד עם

    INSERT <table name> (<columns list>) 

    SELECT ....


    signature   Ronen Ariely
     [Personal Site]    [Blog]    [Facebook]

    • הוצע כתשובה על-ידי Eran Sharvit יום שלישי 11 נובמבר 2014 12:13
    • סומן כתשובה על-ידי Eran Sharvit יום שישי 21 נובמבר 2014 11:48
    יום שלישי 11 נובמבר 2014 10:39
    מנחה דיון
  • הי,

    יש שלושה פתרונות אפשריים למה שאתה צריך.

    הפתרון הראשון עושה שימוש ב-OPENQUERY. הוא ניגש דרך Linked Server לאותו Instance ומריץ את ה-Stored Procedure, אבל אז אתה יכול להשתמש ב-SELECT INTO. אתה צריך לפני זה לאפשר גישה דרך Linked Server לאותו שרת. החיסרון של הפתרון הזה הוא שאתה פותח Connection נוסף לאותו שרת.

    -- Solution #1
    
    USE
    	master;
    GO
    
    
    EXECUTE sys.sp_serveroption
    	@server		= N'YourInstanceName' ,
    	@optname	= 'data access' ,
    	@optvalue	= 'TRUE';
    GO
    
    
    SELECT
    	*
    INTO
    	#ResultsTable
    FROM
    	OPENQUERY ([YourInstanceName] , N'EXECUTE YourDatabaseName.YourSchemaName.YourStoredProcedureName');
    GO
    

    הפתרון השני הוא דומה, אך הוא משתמש ב-OPENROWSET במקום ב-OPENQUERY, ואז אתה לא צריך להשתמש ב-Linked Server, ולא צריך לקנפג את ה-Instance לאפשר גישה דרך Linked Server, כמו שעשינו קודם. מצד שני, אתה צריך לאפשר את "Ad Hoc Distributed Queries". גם כאן, אתה פותח Connection נוסף לאותו שרת.

    -- Solution #2
    
    USE
    	master;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'show advanced options' ,
    	@configvalue	= 1;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'Ad Hoc Distributed Queries' ,
    	@configvalue	= 1;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    EXECUTE sys.sp_configure
    	@configname		= 'show advanced options' ,
    	@configvalue	= 0;
    GO
    
    
    RECONFIGURE;
    GO
    
    
    SELECT
    	*
    INTO
    	#ResultsTable
    FROM
    	OPENROWSET (N'SQLNCLI' , N'Server=YourInstanceName;Trusted_Connection=yes;' , N'EXECUTE YourDatabaseName.YourSchemaName.YourStoredProcedureName');
    GO
    

    הפתרון השלישי משתמש ב-sys.dm_exec_describe_first_result_set_for_object. כאן הרעיון הוא לבנות את הטבלה הזמנית באופן דינמי. במקרה הזה אתה חוסך את ה-Connection הנוסף וגם לא מתערב בשום הגדרה של השרת. אבל הפתרון יותר מסורבל, והבעיה העיקרית היא שהטבלה הזמנית לא מוכרת בקוד החיצוני אלא רק בתוך הקוד הדינמי, ולכן אתה צריך להמשיך לכתוב את הקוד שלך בתוך הקוד הדינמי על מנת שתוכל לגשת לטבלה.

    -- Solution #3
    
    USE
    	YourDatabaseName;
    GO
    
    
    DECLARE
    	@Command AS NVARCHAR(MAX);
    
    SET @Command =
    	N'
    		CREATE TABLE
    			#ResultsTable
    		(
    			';
    
    SELECT
    	@Command +=
    		name + N' ' + UPPER (system_type_name) + N' ' +
    			CASE
    				is_nullable
    			WHEN 0
    				THEN N'NOT NULL'
    			WHEN 1
    				THEN N'NULL'
    			END +
    		N' ,
    			'
    FROM
    	sys.dm_exec_describe_first_result_set_for_object (OBJECT_ID (N'YourSchemaName.YourStoredProcedureName') , 0)
    WHERE
    	is_hidden = 0
    ORDER BY
    	column_ordinal ASC;
    
    SET @Command = LEFT (@Command , LEN (@Command) - 7);
    
    SET @Command +=
    	N'
    		);
    
    		INSERT INTO
    			#ResultsTable
    		EXECUTE YourSchemaName.YourStoredProcedureName;
    	';
    
    EXECUTE sys.sp_executesql
    	@statement = @Command;
    GO
    

    בהצלחה!

    -----------------------------
    גיא גלנצר
    יועץ ומדריך SQL Server
    Madeira - SQL Server Services
    http://www.madeirasql.com

    • סומן כתשובה על-ידי Eran Sharvit יום שישי 21 נובמבר 2014 11:49
    יום שישי 14 נובמבר 2014 02:49
    מנחה דיון