存储过程从c#调用和Merge中的迭代问题

时间:2014-12-04 17:47:42

标签: c# sql-server tsql stored-procedures ado.net

我在列表中有超过一百万条记录。我将所有记录从表传递到存储过程。在存储过程中,我必须迭代以遍历表中的所有行,并且对于每一行,它基于jobid获取表行修改日期并检查它是否存在于数据库中基于它,它更新或插入记录。我觉得我的程序不正确,如果有人帮忙,我会很高兴。

foreach (No_kemi no_list in newforSQL)
{    
    DataTable _dt = new DataTable("table");
    _dt.Columns.Add("JobID", typeof(string));
    _dt.Columns.Add("CreatedDate", typeof(datetime));
    _dt.Columns.Add("ModifiedDate", typeof(datetime));
    _dt.Columns.Add("DbDate", typeof(datetime));
    _dt.Columns.Add("SubGUID", typeof(string));
    _dt.Columns.Add("eType", typeof(string));

    // adding over a million records in the table
    _dt.Rows.Add(no_list.ID,no_list.CreatedDate,no_list.ModifiedDate,no_list.DbDate,no_list.SubGUID,no_list.eType);
}

using (SqlCommand sqlCommand = new SqlCommand())
{
    sqlCommand.CommandType = CommandType.StoredProcedure;
    sqlCommand.CommandText = "Process_NO_table";
    sqlCommand.Connection = connection;

    SqlParameter typeParam = sqlCmd.Parameters.AddWithValue("@track", _dt); 
    typeParam .SqlDbType = SqlDbType.Structured;  
    sqlCmd.ExecuteNonQuery();
}

我的表格类型和程序:

CREATE TYPE TrackType AS TABLE
(
    t_Id uniqueidentifier,  t_JobID  nvarchar(50), t_CreatedDate datetime2(7), t_ModifiedDate datetime2(7), t_DbDate    datetime2(7)
t_SubGUID nvarchar(MAX), t_eType nvarchar(MAX)
);
GO

ALTER/CREATE PROCEDURE [dbo].[Process_NO_table] // i will change to alter after i create it
@track TrackType READONLY
AS
// i need to iterate all the rows of the table(over a million)

Declare @rows INT
Declare @i int = 0
Declare @count int = (SELECT COUNT(*) FROM @track)
DECLARE @is INT

WHILE (@i < @count)
BEGIN    
   -- first i check modified date from the database table 
   SELECT  @is = COUNT(*) FROM NO_table WHERE [JobID] IN (SELECT [t_JobID] FROM @track)
   MERGE [dbo].[NO_table] AS [Target]
   USING @track AS [Source]    

   -- if the database modifed date is less than the modifeid date from the proceduretable(@track) then it updates the records
   ON [Target].[ModifiedDate] < [Source].[t_ModifiedDate] AND JobID = t_JobID
   WHEN MATCHED THEN
   UPDATE SET [JobID] = [Source].[t_JobID],
          [CreatedDate] = [Source].[t_CreatedDate]
          [DbDate]= [Source].[t_DbDate]
          [ModifiedDate] = [Source].[t_ModifiedDate]
          [SubGUID] = [Source].[t_SubGUID] 
          [eType] = [Source].[t_eType]

   -- if the database modifed dateis not existing then it insert the record
   MERGE [dbo].[NO_table] AS [Target]
   USING @track AS [Source]
   ON (@is != 0)
   WHEN NOT MATCHED THEN
       INSERT INTO [NO_table] ( [JobID], [CreatedDate], [ModifiedDate], [DbDate], [SubGUID], [eType]  )
       VALUES ( [Source].[t_JobID], [Source].[t_CreatedDate], [Source].[t_ModifiedDate], [Source].[t_DbDate], [Source].[t_SubGUID], [Source].[t_eType] );

   SET @i = @i + 1
   END
 GO

1 个答案:

答案 0 :(得分:3)

我认为您的SQL中存在大量语法错误(假设MS SQL),但您的合并条件可能会在WHERE附近提供无效语法,因为您需要使用AND而不是WHERE。

ON [Target].[ModifiedDate] < [Source].[t_ModifiedDate] WHERE JobID = t_JobID

应该是

ON [Target].[ModifiedDate] < [Source].[t_ModifiedDate] AND JobID = t_JobID

Select Top 1的空检查后WHEN MATCHED THEN@dbmoddate也需要消失,因为这些也会导致语法问题。

@dbmoddate的空检查后的插入需要指定一个表,因此它实际上知道要插入的内容。

您还需要以分号结束合并语句。

更新的答案

现在你已经清理了这些,我可以更好地了解你正在尝试做什么。在较高级别,您只想更新现有记录,其中修改日期小于自定义类型的修改日期。如果您的表中不存在自定义类型中存在的记录,则将其插入。

话虽如此,你实际上并不需要循环,因为你没有对你的循环做任何事情。您目前所拥有的以及我在此下面发布的内容都是基于集合的结果,而不是迭代结果。

你可以通过删除合并语句并执行一个简单的更新和插入来使这更简单。如果两个语句之间的条件相同(即如果你没有检查修改日期,那么合并就可以了),合并会更有意义,因为那时你可以使用关键字WHEN MATCHEDWHEN NOT MATCHED并将其放在一个合并声明中。我个人远离MERGE声明,因为它们往往是一个小马车,有很多事情你需要注意。

我认为从长远来看这个解决方案会更好,因为它更易于阅读和更易于维护......

CREATE TYPE TrackType AS TABLE
(
t_Id uniqueidentifier,  t_JobID  nvarchar(50), t_CreatedDate datetime2(7), t_ModifiedDate datetime2(7), t_DbDate    datetime2(7)
,t_SubGUID nvarchar(MAX), t_eType nvarchar(MAX)
);
GO


CREATE PROCEDURE [dbo].[Process_NO_table] -- i will change to alter after i create it
@track       TrackType READONLY
AS
-- i need to iterate all the rows of the table(over a million)

Update [NO_table]
SET [JobID] = T.[t_JobID],
    [CreatedDate] = T.[t_CreatedDate],
    [DbDate]= T.[t_DbDate],
    [ModifiedDate] = T.[t_ModifiedDate],
    [SubGUID] = T.[t_SubGUID] ,
    [eType] = T.[t_eType]
From @track T
Where   [NO_table].[JobID] = T.[t_JobID]
And     [NO_table].[ModifiedDate] < T.[t_ModifiedDate]

Insert  [NO_Table]
(
     [JobID], 
     [CreatedDate], 
     [ModifiedDate], 
     [DbDate], 
     [SubGUID], 
     [eType]
)
Select  T.[t_JobID], 
        T.[t_CreatedDate], 
        T.[t_ModifiedDate], 
        T.[t_DbDate], 
        T.[t_SubGUID], 
        T.[t_eType]
From @track T
Where Not Exists (Select 1 From [NO_table] where T.[t_JobID] = [NO_table].[JobID])

 GO