2009-01-19 47 views
1

以下代碼爲要插入的新記錄生成primaey鍵,並將該記錄插入到表中,該表的名稱和要插入的值作爲參數提供給存儲過程。我收到一個運行時錯誤。我使用Visual Studio 2005與SQL Server 2005 Express Edition的工作通用插入存儲過程:運行時錯誤

ALTER PROCEDURE spGenericInsert 

(
    @insValueStr nvarchar(300), 
    @tblName nvarchar(10) 
) 


AS 

DECLARE @sql nvarchar(400) 
DECLARE @params nvarchar(200) 
DECLARE @insPrimaryKey nvarchar(10) 
DECLARE @rowCountVal integer 
DECLARE @prefix nvarchar(5) 

--following gets the rowcount of the table-- 
SELECT @rowCountVal = ISNULL(SUM(spart.rows), 0) 
    FROM sys.partitions spart 
    WHERE spart.object_id = object_id(@tblName) AND spart.index_id < 2 

SET @rowCountVal = @rowCountVal+1 




--Following Creates the Primary Key-- 
IF @tblName = 'DEFECT_LOG' 
    SET @prefix='DEF_' 
ELSE IF @tblName='INV_Allocation_DB' 
    SET @prefix='INV_' 
ELSE IF @tblName='REQ_Master_DB' 
    SET @prefix='REQ_' 
ELSE IF @tblName='SW_Master_DB' 
    SET @prefix='SWI_' 
ELSE IF @tblName='HW_Master_DB' 
    SET @prefix='HWI_' 


SET @insPrimaryKey= @prefix + RIGHT(replicate('0',5)+ convert(varchar(5),@rowCountVal),5) -- returns somethin like 'DEF_00005' 


-- Following is for inserting into the table -- 

SELECT @sql = N' INSERT INTO @tableName VALUES ' + 
     N' (@PrimaryKey , @ValueStr)' 

SELECT @params = N'@tableName nvarchar(10), ' + 
        N'@PrimaryKey nvarchar(10), ' + 
        N'@ValueStr nvarchar(300)' 

EXEC sp_executesql @sql, @params, @[email protected], @[email protected], @[email protected] 

輸出消息:

Running [dbo].[spGenericInsert] (@insValueStr = 2,"Hi",1/1/1987, @tblName = DEFECT_LOG). 

Must declare the table variable "@tableName". 

No rows affected. 

(0 row(s) returned) 

@RETURN_VALUE = 0 

Finished running [dbo].[spGenericInsert]. 

回答

4

你將不得不直接串聯表名稱爲字符串,因爲這不能參數化:

SELECT @sql = N' INSERT INTO [' + @tblName + '] VALUES ' + 
      N' (@PrimaryKey , @ValueStr)' 

SELECT @params = N'@PrimaryKey nvarchar(10), ' + 
       N'@ValueStr nvarchar(300)' 

爲了防止注入攻擊,您應該列出這個表名。如果表中還有其他不可空的列,這也不穩健。

note:雖然我個人認爲這不是TSQL的良好用法;在客戶端(C#或其他)中構建命令可能更合適,並將其作爲參數化命令執行。有動態SQL的用例,但我不確定這是一個很好的例子。更好的是,使用你喜歡的ORM工具(LINQ-to-SQL,NHibernate,LLBLGen,Entity Framework等)爲你做這一切,並專注於你的實際問題領域。

+0

什麼是白名單表名? – 2009-01-19 13:24:31

0

白名單本質上是指確保傳入的表是您希望它們能夠插入的有效表。我們只是爲了參數而說出表名是用戶提供的,然後用戶可以開始將記錄插入到系統表中。

SELECT * FROM系統對象,其中名稱= @ tblname和的xtype =「U」

然而正如馬克建議是這樣的:

可以通過回彈sysobjects表的表名做一個白名單檢查不是很好的使用TSQL,你最好在應用程序層處理這個問題作爲一個paramatized查詢。

0

同意Marc-總的來說這是一個非常糟糕的主意。通用插入/更新或刪除最終導致數據庫問題。

另一個問題是,當兩個用戶在同一張表上同時運行時,這個過程會遇到問題,因爲他們會嘗試插入相同的主鍵。

相關問題