逐行更新SQL表中的数据

时间:2014-12-02 08:47:13

标签: sql sql-server stored-procedures sql-server-2008-r2

我正在使用SQL Server 2008 R2。我有一个来自链接服务器的View [EmployeeMaster]和一个数据库中的表[EmployeeDetails]。我有一项服务,每天早上12点运行,调用一个存储过程,使表与视图同步。即,存储过程检查并使用视图中的匹配行更新[EmployeeDetails]中的每一行。我的存储过程是这样的。

CREATE PROCEDURE usp_OracleSyncUpdate
AS

CREATE TABLE #ActiveEmployees (
 RowID int IDENTITY(1, 1), 
 [EmployeeId] nvarchar(50),
)
DECLARE @NumberRecords int, @RowCount int
DECLARE @EmployeeId nvarchar(50)
        ,@EmployeeName nvarchar(50)
        ,@EmployeeLastName nvarchar(50)
        ,@EmployeeCategory nvarchar(50)
        ,@ContactNo nvarchar(50)
        ,@Email nvarchar(50)
        ,@Gender nvarchar(50)
        ,@JoiningDate DATETIME

-- into the temporary table
INSERT INTO #ActiveEmployees ([EmployeeId])
SELECT [EMPLOYEE_NUMBER]
FROM [dbo].[EmployeeMaster]
WHERE [EMPLOYEE_NUMBER] IN (
        SELECT EmployeeId
        FROM [dbo].[EmployeeDetails]
        )

-- Get the number of records in the temporary table
SET @NumberRecords = @@ROWCOUNT
SET @RowCount = 1

-- loop through all records in the temporary table
-- using the WHILE loop construct
WHILE @RowCount <= @NumberRecords
BEGIN
 SELECT @EmployeeId = EmployeeId
 FROM #ActiveEmployees
 WHERE RowID = @RowCount

 SELECT @EmployeeName = EmployeeName FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId
 IF(LTRIM(RTRIM(@EmployeeName)) <> (SELECT LTRIM(RTRIM([FIRST_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET EmployeeName = (SELECT LTRIM(RTRIM([FIRST_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)
        WHERE EmployeeId = @EmployeeId
    END
 SELECT @EmployeeLastName = EmployeeLastName FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId
 IF(LTRIM(RTRIM(@EmployeeLastName)) <> (SELECT LTRIM(RTRIM([LAST_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET EmployeeLastName = (SELECT LTRIM(RTRIM([LAST_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)
        WHERE EmployeeId = @EmployeeId
    END
 SELECT @EmployeeCategory = [Category] FROM [dbo].[EmployeeCategory] WHERE [EmployeeCategoryId] = (SELECT [EmployeeCategoryId] FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId)
 IF(LTRIM(RTRIM(@EmployeeCategory)) <> (SELECT LTRIM(RTRIM([JOB_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET [EmployeeCategoryId] = (SELECT [EmployeeCategoryId] FROM [dbo].[EmployeeCategory] WHERE [Category] = (SELECT LTRIM(RTRIM([JOB_NAME])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)) 
        WHERE EmployeeId = @EmployeeId
    END
 SELECT @Email = Email FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId
 IF(LTRIM(RTRIM(@Email)) <> (SELECT LTRIM(RTRIM([EMAIL_ADDRESS])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET Email = (SELECT LTRIM(RTRIM([EMAIL_ADDRESS])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)
        WHERE EmployeeId = @EmployeeId
    END
 SELECT @Gender = Gender FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId
 IF(LTRIM(RTRIM(@Gender)) <> (SELECT LTRIM(RTRIM([GENDER])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET Gender = (SELECT LTRIM(RTRIM([GENDER])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)
        WHERE EmployeeId = @EmployeeId
    END
 SELECT @JoiningDate = JoiningDate FROM [dbo].[EmployeeDetails] WHERE [EmployeeId] = @EmployeeId
 IF(LTRIM(RTRIM(@JoiningDate)) <> (SELECT LTRIM(RTRIM([DATE_OF_JOINING])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId))
    BEGIN
        UPDATE [dbo].[EmployeeDetails] SET JoiningDate = (SELECT LTRIM(RTRIM([DATE_OF_JOINING])) FROM [dbo].[EmployeeMaster] WHERE [EMPLOYEE_NUMBER] = @EmployeeId)
        WHERE EmployeeId = @EmployeeId
    END

 SET @RowCount = @RowCount + 1
END

-- drop the temporary table
DROP TABLE #ActiveEmployees

它正在工作,它会更新列。现在该表有26196条记录,执行此存储过程大约需要23:56分钟。将来,记录将不断增加,执行时间将更长。

  1. 有没有办法缩短执行时间(建议对查询进行一些优化)?
  2. 或者还有其他方法可以同步这两张桌子吗?
  3. 或者有没有办法计算未来的执行时间,我可以根据它设置连接超时?
  4. 这是我的最终代码

        alter PROCEDURE usp_OracleSyncUpdate
    AS
        UPDATE ed
        SET ed.[EmployeeName] = LTRIM(RTRIM(em.FIRST_NAME)),
            ed.EmployeeLastName = LTRIM(RTRIM(em.LAST_NAME)), 
                ed.EmployeeCategoryId = ec.EmployeeCategoryId,
                ed.Email = isnull(ed.Email,em.[EMAIL_ADDRESS]),
                ed.[ContactNo] = isnull(ed.[ContactNo],em.ContactNo),
                ed.Gender = em.Gender,
                ed.JoiningDate = em.[DATE_OF_JOINING]
            FROM dbo.EmployeeDetails ed
            INNER JOIN [EmployeeMaster] em ON ed.EmployeeId = em.[EMPLOYEE_NUMBER]
            INNER JOIN dbo.EmployeeCategory ec ON ec.Category = em.[JOB_NAME]
    

    谢谢@marc_s

2 个答案:

答案 0 :(得分:3)

摆脱 RBAR (逐行排列)处理 - 关系数据库工作成套数据 - 使用单个基于集合 UPDATE声明,您已完成。

有些事情:

CREATE PROCEDURE usp_OracleSyncUpdate
AS
    CREATE TABLE #ActiveEmployees (
     RowID int IDENTITY(1, 1), 
     [EmployeeId] nvarchar(50),
    )

    -- into the temporary table
    INSERT INTO #ActiveEmployees ([EmployeeId])
      SELECT [EMPLOYEE_NUMBER]
      FROM [dbo].[EmployeeMaster]
      WHERE [EMPLOYEE_NUMBER] IN (SELECT EmployeeId
                              FROM [dbo].[EmployeeDetails])

    UPDATE dbo.EmployeeDetails
    SET ed.EmployeeName = LTRIM(RTRIM(ae.FIRST_NAME)),
        ed.EmployeeLastName = (SELECT LTRIM(RTRIM(ae.LAST_NAME)), 
            ed.EmployeeCategoryId = ec.EmployeeCategoryId,
            ed.Email = ae.Email,
            ed.Gender = ae.Gender,
            ed.JoiningDate = ae.JoiningDate
        FROM dbo.EmployeeDetails ed
        INNER JOIN #ActiveEmployees ae ON ed.EmployeeId = ae.EmployeeId
        INNER JOIN dbo.EmployeeCategory ec ON .......
        WHERE EmployeeId = @EmployeeId

我不知道EmployeeCategory表如何与其他表相关联 - 您需要在JOIN行添加INNER JOIN条件。< / p>

另外,很可能,您也可以消除该临时表,只需直接从EmployeeDetails更新EmployeeMaster,这是节省内存和处理时间的第二步。< / p>

答案 1 :(得分:2)

好吧,而不是循环在一个sql语句中执行它并完成它。严重。

我看到一个循环,我看到了大量的个人陈述,我可以设想只有一个更新声明。

最重要的是,这不是“休表”。它很小。超级小。一百万行很小。这甚至没有27000行。你只是通过制作“程序员方法” - 循环来滥用服务器,方式太多了。使用基于集合的方法,您的整个循环可以写成一个声明。