合并插入Sproc中的MERGE问题

时间:2013-08-13 15:14:38

标签: sql sql-server sql-server-2008

我的“合并”问题: MERGE语句尝试多次更新或删除同一行。

有人可以帮我解决这个问题,因为我不明白如何纠正这个问题:

ALTER PROCEDURE [Files].[ImportFiles]
AS
    -- Create a temporary table for the bulk import
    CREATE TABLE #TempImportFileTable(
        [fileID] [bigint] IDENTITY(1,1) NOT NULL,
        [FileName] [nvarchar](max) NULL,
        [FilePath] [nvarchar](max) NULL,
        [FullPath] [nvarchar](max) NULL,
        [FileSize] [nvarchar](max) NULL,
        [FileExtension] [nvarchar](max) NULL,
        [FileCreated] [nvarchar](max) NULL,
        [FileLastAccessed] [nvarchar](max) NULL,
        [FileModified] [nvarchar](max) NULL
     CONSTRAINT [PK_fileID1] PRIMARY KEY CLUSTERED 
    (
        [fileID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY];

    -- Import into the temp table
    BULK INSERT #TempImportFileTable FROM 'C:\Program Files\o7th FileSystem to DB\import.txt' 
    WITH(KEEPIDENTITY, FIELDTERMINATOR =',', ROWTERMINATOR = '\n');

    -- Delete the Duplicate entries
    DELETE FROM #TempImportFileTable WHERE fileID NOT IN (SELECT MAX(fileID) FROM #TempImportFileTable GROUP BY FullPath);


    -- Now Merge the 2 tables
    MERGE [Files].[File] AS TargetTable
    USING #TempImportFileTable AS SourceTable  
    ON (TargetTable.FullPath = SourceTable.FullPath)
    WHEN NOT MATCHED BY TARGET                                
        THEN INSERT (FileName, FilePath, FileSize, FileExtension, FileCreated, FileLastAccessed, FileModified)
        VALUES(SourceTable.FileName, SourceTable.FilePath, SourceTable.FileSize, SourceTable.FileExtension, SourceTable.FileCreated, SourceTable.FileLastAccessed, SourceTable.FileModified)
    WHEN MATCHED                                              
        THEN UPDATE SET
            TargetTable.FileName = SourceTable.FileName,
            TargetTable.FilePath = SourceTable.FilePath,
            TargetTable.FileSize = SourceTable.FileSize,
            TargetTable.FileExtension = SourceTable.FileExtension,
            TargetTable.FileCreated = SourceTable.FileCreated,
            TargetTable.FileLastAccessed = SourceTable.FileLastAccessed,
            TargetTable.FileModified = SourceTable.FileModified;

2 个答案:

答案 0 :(得分:1)

所以你的#TempFileTable中有重复项。

如果FileName + FilePath足以使行唯一,则可以将此条件用于MERGE:

MERGE [Files].[File] AS TargetTable
    USING #TempFileTable AS SourceTable  
    ON ( 
        ISNULL(TargetTable.FileName,'') = ISNULL(SourceTable.FileName,'') 
        AND ISNULL(TargetTable.FileName,'') = ISNULL(SourceTable.FileName,'') 
    )

(我不知道为什么ISNULL()函数在你之前尝试调用它时不起作用,但它肯定应该以这种方式工作,并处理空值出现的问题。)

如果您的原始文件中确实存在重复的行并且想要删除它们,则可以使用此类代码:

DELETE FROM #TempFileTable WHERE fileID IN (
    SELECT u.fileID FROM(
        select fileID, ROW_NUMBER() OVER(PARTITION BY FileName, FilePath OVER fileID) as r_number 
        FROM #TempFileTable
    ) where u.r_number>1
)

很难看,但是当多行具有相同的FileName和相同的FilePath时,它将删除具有最高fileID的行并且只保留一行。

编辑:关于性能问题,首先尝试查看估计的执行计划,看看是否可以向表中添加索引。您还可以尝试将MERGE过程分解为INSERT和一个UPDATE语句。 MERGE应该更好,但在某些情况下,它实际上比单独的陈述更糟糕。

答案 1 :(得分:0)

合并语句有一个限制,即它不能多次更新同一行,或者更新和删除同一行。因此,请确保源数据中包含带有文件名的不同行。 此外,在进行更新时,您不必更新文件名列,因为它在源表和目标表中都是相同的。

您可以通过以下链接找到解决方法:http://support.microsoft.com/kb/976316