在存储过程中使用多个内部联接与XML数据进行T-SQL合并

时间:2017-06-22 19:53:10

标签: c# sql sql-server tsql asp.net-mvc-5

我对T-SQL比较新,我在运行导入MERGE存储过程时遇到了一些麻烦。我确定这是一个简单的错误,但我一直在阅读一篇文章,试图找出我的错误。

我将全面介绍我正在做什么(或尝试做什么)以便一切都有意义。此应用程序的目的是查看已收到营销电子邮件并最近根据该电子邮件购买服务/产品的成员列表。

让我们调用此应用程序" MktRep "这是使用Visual Studios 2017社区版在 C#MVC 5 - ASP.NET 中创建的。对于数据库,我使用 SQL Server Management Studios 2014 。继续。

MktRep 有两个主要视图/页面(实际上有多个部分视图):

  1. 导入数据的一页
  2. 查看数据的一页
  3. 好的,让我们继续吧。现在,当用户导入数据时,它们提供以下信息:

    • 包含成员帐号的CSV文件
    • 邮件发送日期
    • 发送的邮件的类型(我们目前有2种不同的类型)

    导入CSV文件后,我们将其转换为XML格式,然后将该数据与其他收集的数据一起通过存储过程传递到数据库INSERT / UPDATE / MERGE。

    现在,从数据库方面,我们有多个表(和数据库)提供特定的帐户详细信息,并为所有导入的数据创建一个新表。

    最初,我使用导入的值,比较帐号,产品预订日期和邮寄日期,并将匹配项存储在此新表中。但是,我意识到这是一个坏主意,因为如果会员在上传日期之后预订/购买了服务,那么该数据将会丢失并且可能存在差异。所以,我等待进行比较直到"查看报告"页。

    所以,我遇到了问题。

    当我们导入帐户数据时,我们不希望有重复记录。但是,如果记录已经存在,我们想要更新字母类型和邮寄日期。

    在阅读了关于使用UPDATE / INSERT,MERGE以及介于两者之间的所有内容的TON之后,我决定尝试使用MERGE。

    目前,只要XML中有超过1000条记录,查询就需要差不多一分钟才能运行。有关如何减少时间的任何想法?

    为了测试代码,我将其作为常规SQL查询运行,但顶部定义的变量通常是从Web应用程序传递的变量。

    SQL代码:

    BEGIN
    DECLARE 
        @maildate date = '04-01-2017',
        @lettertype varchar(10) = 'ALR',
        @xmldata varchar(max) = '<data>
                                    <rec><mem> 400117788 </mem></rec>
                                    <rec><mem> 122244455 </mem></rec>
                                    <rec><mem> 188642145 </mem></rec>
                                    <rec><mem> 348865442 </mem></rec>
                                    <rec><mem> 199754621 </mem></rec>
                                    <rec><mem> 955421234 </mem></rec>
                                    <rec><mem> 754136845 </mem></rec>
                                    <rec><mem> 946612164 </mem></rec>
                                    <rec><mem> 102446785 </mem></rec>
                                    <rec><mem> 478310246 </mem></rec></data>'
    
    /*----------------------------*/
    /*-- GET MEM DATA FROM XML --*/
    /*----------------------------*/
    
    DECLARE @memData TABLE 
    (
        mem varchar(9)
    )
    
    DECLARE @num int
    
    EXEC sp_xml_preparedocument @num OUTPUT, @xmldata
    
    INSERT INTO @memData
    
    SELECT * FROM OPENXML (@num, '/data/rec',2)
    
    WITH (mem varchar(9))
    
    EXEC sp_xml_removedocument @num
    
    
    /*-------------------------------*/
    /*-- INSERT DATA INTO TEMP TBL --*/
    /*-------------------------------*/
    DECLARE @tempData TABLE
    (
        account varchar(10),
        mem varchar(9),
        maildate date,
        lettertype varchar(5)
    )
    
    INSERT into @tempData (account, mem, lettertype, maildate)
    
    SELECT
    
        s.account, s.mem, @lettertype, @maildate
    
    FROM
        [tsqldb\sqldb].sumdb.dbo.tblShareFile s
    
    INNER JOIN [tsqldb\sqldb].sumdb.dbo.tblServiceFile l
    
        ON l.account = s.account
    
    INNER JOIN @memData d
    
        ON d.mem = s.mem
    
    WHERE
    
        s.AccFlag != 80
    
        AND s.AccType = '0' 
    
    
    /*----------------------------------*/
    /*-- CHECK FOR DUPS & INSERT DATA --*/
    /*----------------------------------*/
    
    MERGE INTO dbo.tblMktRep AS TARGET
    
    USING @tempData AS source
    
    ON source.account = target.Account
    
        WHEN NOT MATCHED BY TARGET THEN
            INSERT (Account, mem, lettertype, MailedDate)
            VALUES (source.account, source.mem, source.lettertype, source.maildate)
    
        WHEN MATCHED AND (target.MailedDate < source.maildate) THEN 
            UPDATE 
            SET 
                target.lettertype = source.lettertype,
                target.MailedDate = source.maildate;
    

    更新:我发现我得到的错误是因为&#34; BEGIN&#34;。一旦我删除它,它运行正常。现在唯一的问题是为什么它需要这么长时间才能运行。

    更新:我现在收到以下错误:

    Msg 8672, Level 16, State 1, Line 67
    The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
    

    我已阅读其他帖子和文章,但仍然没有找到解决方案:

    SQL Server MERGE + Joining other tables

    one from msdn

    one from sql sunday

    one from technet

    one from sqljana

2 个答案:

答案 0 :(得分:2)

我的陈述中没有看到END条款。一旦我添加了END,它就可以在我的系统上解析。

如果没有结束END的BEGIN将在最后一个语句的末尾生成语法错误。

更新问题后

尝试将您的表变量更改为在Account上具有聚簇索引的临时表。表变量通常不能很好地处理大量数据。

要解决多行更新问题,您需要确保源只有一个帐户,因为这是您的匹配键。如果帐户多次出现在源中,则可能会多次触发同一行的update子句。由于您的源maildate是一个变量,您应该可以使用SELECT DISTINCT在源表中解决此问题

答案 1 :(得分:0)

我的朋友......你有一个开始,没有结束......