循环遍历动态DataSet并插入存储过程

时间:2014-04-01 11:48:09

标签: c# sql sql-server stored-procedures datatable

我在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:如果上述场景中还有其他方法更容易,请告诉我。

感谢。

3 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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

答案 2 :(得分:0)

这可能有用。只需使用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