2013-10-07 120 views
3

我想在存儲過程中使用動態SQL來創建表格。使用動態sql創建表格

這裏是調用存儲過程:

EXEC [spCreateAColDiffTable] 'hq193.dbo.arch_con_col_s193_s202' 

這裏是存儲過程的相關部分:

CREATE PROCEDURE sp_createAColDiffTable (@table_name nvarchar(128)) 

...

SET @sSQL = 'CREATE TABLE ' + @table_name + ' (' + 
' [table_name]  VARCHAR (128) NOT NULL, ' + 
' [column_name]  VARCHAR (128) NULL, ' + 
' [what_changed]  VARCHAR (128) NULL, ' + 
' [sr_data_type]  VARCHAR (128) NOT NULL, ' + 
' [tr_data_type]  VARCHAR (128) NOT NULL, ' + 
' [sr_max_length] SMALLINT NOT NULL, ' + 
' [tr_max_length] SMALLINT NOT NULL, ' + 
' [sr_is_nullable] CHAR NULL, ' + 
' [tr_is_nullable] CHAR NULL, ' + 
' [sr_precision]  SMALLINT NULL, ' + 
' [tr_precision]  SMALLINT NULL, ' + 
' [sr_scale]   SMALLINT NULL, ' + 
' [tr_scale]   SMALLINT NULL) ' + 
' ON [PRIMARY] WITH (DATA_COMPRESSION = NONE)' 
PRINT @sSQL 
Exec @sSQL 

GO

當我跑步存儲過程我收到錯誤:在存儲的步驟之前執行我它我打印出SQL

SQL Server Database Error: The name 'CREATE TABLE hq193.dbo.arch_con_col_s193_s202 ([table_name] VARCHAR (128) NOT NULL, [column_name] VARCHAR (128) NULL, [what_changed] VARCHAR (128) NULL, [sr_data_type] VARCHAR (128) NOT NULL, [tr_data_type] VARCHAR (128) NOT NULL, [sr_max_length] SMALLINT NOT NULL, [tr_max_length] SMALLINT NOT NULL, [sr_is_nullable] CHAR NULL, [tr_is_nullable] CHAR NULL, [sr_precision] SMALLINT NULL, [tr_precision] SMALLINT NULL, [sr_scale] SMALLINT NULL, [tr_scale] SMALLINT NULL) ON [PRIMARY] WITH (DATA_COMPRESSION = NONE)'

is not a valid identifier.

的通知。如果我將要打印的SQL剪切並粘貼到查詢編輯器窗口中,它可以正常工作。

我錯過了什麼?

回答

13

試試這樣說:

EXEC(@sSQL) 

這是一個很常見的錯誤。如果沒有括號,EXEC @sSQL意味着「執行存儲過程,其名稱是在@sSQL變量」,而不是你想要的東西這可能是「在變量@sSQL執行的命令字符串。

+1

雖然答案是正確的,我會建議使用'EXEC sp_executesql的@ sSQL'動態SQL。有關更多信息,請參見[this](http://www.sommarskog.se/dynamic_sql.html)。 – seph

+1

我對Erland的工作和編寫非常熟悉,並且我沒有意識到在這種情況下使用'sp_ExecuteSql'超過'EXEC(..)'的好理由。由於它的本性,我認爲這是一個操作過程,並不適用於Apps/OLTP,所以SQL注入應該不是問題(無論如何,單獨使用sp_ExecuteSql本身並不能解決這個問題)。至於性能,這是DDL,因此預編譯查詢計劃的優勢在這裏不起作用。 – RBarryYoung

+4

我更喜歡sp_executesql,因爲它提供了一個好習慣。爲什麼在一個重要的方法和另一個不重要的方法中使用一種方法,而不是總是使用可能很重要的方法? –

1

我看到這是一箇舊帖子,但我有一個類似的問題,我需要閱讀一個文本文件,其中的列可能會因爲文件被拖動的方式而有所改變。所以我編寫了一個程序來讀取文本文件,並將其放入一個動態創建的臨時表中,以便我可以處理輸出。

或許這可以幫助別人..

DECLARE @NUM_COL AS INT 
DECLARE @I   AS INT 
DECLARE @CREATE_TBL AS NVARCHAR(MAX) 
DECLARE @DATA  AS NVARCHAR (MAX) 
DECLARE @XML_ROW AS XML 
DECLARE @MAX_CHAR AS INT 

--Sets the column max characters for temp table ##FILE_TABLE 
SET @MAX_CHAR = 1000 

--File import of data as single rows, no columns 
IF OBJECT_ID('tempdb..#FILE_ROWS') IS NOT NULL 
DROP TABLE #FILE_ROWS 

CREATE TABLE #FILE_ROWS 
    ([Row_data] NVARCHAR(MAX) NULL) 


--Global temp table used because the table is being built dynamically. 
IF OBJECT_ID('tempdb..##FILE_TABLE') IS NOT NULL 
DROP TABLE ##FILE_TABLE 

--This is only so the debugger thinks the table is created when referenced in later SQL code. 
IF 1 <> 1 CREATE TABLE ##FILE_TABLE (X INT) 

BULK INSERT #FILE_ROWS 
FROM 'C:\Users\Wayne\Desktop\777434633016764.txt' 
WITH 
(
    FIELDTERMINATOR = '\t' --Tab Delimited 
,ROWTERMINATOR = '\n' 
) 

--Figures out how many columns were in the file. 
SET @NUM_COL = (SELECT MAX(LEN(Row_data) - LEN(REPLACE(Row_data, CHAR(9), ''))) + 1 AS [NO_COL] FROM #FILE_ROWS) 

SET @CREATE_TBL = 'CREATE TABLE ##FILE_TABLE (ID INT IDENTITY(1,1),' 
SET @I = 1 

Declare COUNTER Cursor for 
     SELECT 
      CAST('<A>' + REPLACE(Row_data, CHAR(9), '</A><A>') + '</A>' AS XML) 
     FROM #FILE_ROWS 
open COUNTER 
     fetch next from COUNTER into @XML_ROW 
     while @@fetch_Status != -1 
     begin 

      IF @I = 1 
      BEGIN 
       SELECT @CREATE_TBL = @CREATE_TBL 
            + '[' + REPLACE(dbo.Trim(DATA.value('.','char(30)')), N'''', '`') 
            + ']' + ' NVARCHAR(' + CAST(@MAX_CHAR AS NVARCHAR(5)) + ') NULL,' 
       FROM @XML_ROW.nodes('/A') AS x(DATA) 

       SET @CREATE_TBL = LEFT(@CREATE_TBL, LEN(@CREATE_TBL) - 1) + ')' 

       EXEC(@CREATE_TBL) 

       SET @I = 2 
      END 
      --ELSE --If you do not want the column names in the first row, remove the ELSE 
      BEGIN 
       SET @DATA = 'INSERT INTO ##FILE_TABLE SELECT ' 
       SELECT @DATA = @DATA 
           + '''' + REPLACE(dbo.Trim(DATA.value('.','char(30)')), N'''', '`') 
           + '''' + ',' 
       FROM @XML_ROW.nodes('/A') AS x(DATA) 

       SET @DATA = LEFT(@DATA, LEN(@DATA) -1) 

       EXEC(@DATA) 
      END 

      FETCH NEXT FROM COUNTER INTO @XML_ROW 
     END 
CLOSE COUNTER 
DEALLOCATE COUNTER 

SELECT * from ##FILE_TABLE