2014-04-01 128 views
0

我有一個C#中的DataTable,我需要插入到表中。 DataTable是完全動態的(列沒有預先定義)。我使用C#代碼逐行插入此DataTable,但由於效率低下,我正在將DataTable批量發送到SQL存儲過程。我需要存儲過程循環遍歷,逐行插入,並返回無效數據集。循環通過動態數據集並插入存儲過程

C#代碼:

SqlConnection sqlConnection = getDBConnection(); 
SqlCommand command = sqlConnection.CreateCommand(); 

command.CommandType = System.Data.CommandType.StoredProcedure; 
command.CommandText = "[dbo].[saveDataIntoTable]"; 

SqlParameter parameter = new SqlParameter(); 

//The parameter for the SP must be of SqlDbType.Structured 
parameter.ParameterName = "@Sample"; 
parameter.SqlDbType = System.Data.SqlDbType.Structured; 
parameter.Value = dataTable; 

command.Parameters.Add(parameter); 

     foreach (DataRow row in dataTable.Rows) 
     { 
      System.Diagnostics.Debug.WriteLine(row.ItemArray); 
      if (row.ItemArray[0] == null) 
      { 
       dataTable.Rows.Remove(row); 
      } 
     } 

SqlDataReader dr = command.ExecuteReader(); 
DataTable dt = new DataTable(); 
dt.Load(dr); 

//handling the dt DataTable here 

存儲過程:

USE [DATABASE_NAME] 
GO 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE [dbo].[saveDataIntoTable] 
(
    -- which accepts one table value parameter. It should be noted that the parameter is readonly 
    @Sample As [dbo].[SampleUserData] Readonly 
) 
AS 
BEGIN 

BEGIN TRY 

    Insert Into USER(USER_ID,EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE) 
     Select USER_ID, EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE From @Sample 

END TRY 
BEGIN CATCH 
    Select USER_ID, EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE From @Sample 
END CATCH 
END 

我用於存儲過程的一個用戶定義的表類型:

-- Create a table data type 
CREATE TYPE [dbo].[SampleUserData] As Table 
(
     --This type has structure similar to the DB table   
     USER_ID Nvarchar(20) , 
     EMAIL Nvarchar(50), 
     PASSWORD Nvarchar(100), 

     PASSWORD_HINT Nvarchar(20), 
     PWD_CHANGED_DATE date, 
     CREATED_BY Nvarchar(20), 

     CREATED_DATE date, 
     UPDATED_BY Nvarchar(20), 
     UPDATED_DATE date, 
     STATUS Nvarchar(20), 
     VERSION Int, 
     VALIDATE Nvarchar(10) 

); 

現在,我的存儲過程一次插入整個數據。當發生異常時,它會返回整個DataSet(我不知道如何分隔行)。

PS:如果上述場景有其他方法比較容易,請告訴我。

謝謝。

回答

0

爲什麼不使用where子句來驗證數據

-- insert valid data 
insert into [USER] (USER_ID,EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
        CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE) 
select USER_ID, EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE 
from @Sample 
where USER_ID is not null 

-- select invalid data 
select USER_ID, EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE 
from @Sample 
where USER_ID is null 

更詳細的驗證檢查的一個例子

select USER_ID, EMAIL,PASSWORD,PASSWORD_HINT,PWD_CHANGED_DATE, 
     CREATED_BY,CREATED_DATE,UPDATED_BY,UPDATED_DATE,STATUS,VERSION,VALIDATE 
from @Sample S 
where USER_ID is not null 
and EMAIL is not null 
and PASSWORD is not null -- etc 
-- check record is not duplicate 
and not exists (select 1 from [USER] U where U.USER_ID = S.USER_ID) 
and isnumeric(USER_ID) 
+0

啊,但我怎麼可以用它來檢查數據類型驗證,驗證無效,重複的字段都在一次?這就是我使用try catch塊的原因。 –

+0

@DilangaThalpegama你是什麼意思的重複字段?空驗證當然可以在where子句中處理,數據類型驗證在一定程度上也可以重複記錄。 –

+0

我不能使用where子句,因爲正如我所說DataSet是**動態生成**。我不知道列名或任何其他約束。這是使用try catch塊的原因。我試圖使用遊標來循環通過作爲參數收到的DataSet。你能幫我嗎? –

0

這將在同一時間做同樣爲您的存儲過程一行: 這是爲SQL Server 2005編寫的

BEGIN 
--I'm only using your first three columns in this example 
DECLARE @USER_ID as Nvarchar(20); 
DECLARE @Email as Nvarchar(20); 
DECLARE @Password as Nvarchar(20); 
DECLARE @SampleCursor as CURSOR; 

SET @SampleCursor = CURSOR FOR 
SELECT USER_ID, EMAIL, PASSWORD 
FROM @Sample; 
OPEN @SampleCursor; 
--Can't insert directly into table from table variable so save as scalar variable first 
FETCH NEXT FROM @SampleCursor INTO @USER_ID, @Email, @Password; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
FETCH NEXT FROM @SampleCursor INTO @USER_ID, @Email, @Password; 
BEGIN TRY 
--then insert scalar variables into table 
INSERT INTO USER (USER_ID, Email, Password) VALUES(@USER_ID, @Email, @Password) 
END TRY 
BEGIN CATCH 
SELECT @USER_ID, @Email, @Password 
END CATCH 
END 

CLOSE @SampleCursor; 
DEALLOCATE @SampleCursor; 
END 
+0

感謝這有正確的方法,但我怎麼可以使用這樣的事情: SET @SampleCursor = CURSOR for SELECT * FROM @Sample; 沒有選擇一組特定的列。原因是,即使我在問題中專門設置了列名,但我不會在運行時列名。 –

+0

因此,因爲列是動態的,所以我不能使用這個: DECLARE USER_ID作爲Nvarchar(20); DECLARE Email作爲Nvarchar(20); 將密碼DECLARE作爲Nvarchar(20); –

+0

如何在C#中動態創建存儲過程然後執行它? http://msdn.microsoft.com/en-us/library/vstudio/zxsa8hkf%28v=vs.100%29.aspx –

0

這個mi ght工作。只需使用TOP(1)一次插入一行源表。下面的解決方案暫時創建一個表,因此您的源表不會被刪除。

--create copy of source table 
SELECT * INTO TempTbl FROM Source_Table 
--loop through temp table 
WHILE EXISTS (SELECT * FROM TempTbl) 
BEGIN 
--insert first line of temp table into destination table 
BEGIN TRY 
INSERT INTO [USER] SELECT TOP (1) * FROM TempTbl 
END TRY 
BEGIN CATCH 
SELECT TOP(1) FROM TempTbl 
END CATCH 
--remove inserted line from temp table 
DELETE TOP (1) FROM TempTbl 
END 
DROP TABLE TempTbl 

更新。

這個工作對我來說:

CREATE PROCEDURE SOProc 
    -- Add the parameters for the stored procedure here 
    @Source_Table_Name sysname = '' 
AS 
BEGIN 
EXEC(
'SELECT * INTO TempTbl FROM ' + @Source_Table_Name) 
WHILE EXISTS (SELECT * FROM TempTbl) 
BEGIN 
BEGIN TRY 
INSERT INTO User_Table SELECT TOP (1) * FROM TempTbl 
END TRY 
BEGIN CATCH 
SELECT TOP(1) * FROM TempTbl 
END CATCH 
DELETE TOP (1) FROM TempTbl 
END 
DROP TABLE TempTbl 
END 
GO 
+0

謝謝,這可能是正確的方法,但如果Source_Table是參數,我應該如何編輯sql以將數據插入臨時表:像'SELECT * INTO TempTbl FROM @ SourceTableParam'? 我嘗試使用'EXEC('SELECT * INTO TempTbl FROM'+ @TableNameParam)',但其他引用失敗,因爲'TempTbl'參數未聲明 –

+0

使用表名作爲參數執行上述操作。注意'SELECT * INTO TempTbl FROM'之後的空格 –