【问题标题】:T-SQL Merge from multiple source records来自多个源记录的 T-SQL 合并
【发布时间】:2018-08-01 15:16:02
【问题描述】:

我看过几个类似的问题,但没有找到一个可以回答我的问题。

我有一个源表,其中包含公司的许多单独注释

CompanyName, Notes3
Company1, "spoke with someone"
Company2, "Email no longer works"
Company1, "Moved address"

我有一个目标表(vchCompanyName 在这里是唯一的)

vchCompanyName, vchNotes
Company1, "started business in 2005"
Company2, null

我想结束

vchCompanyName, vchNotes
Company1, "started business in 2005
           spoke with someone
           Moved address"
Company2, "Email no longer works"

我试过这个代码

WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
    FROM CompanyContact
    )

    merge dCompany as target
    using CTE as source
    on target.vchcompanyname = source.companyname 
    when matched and len(source.notes3)>0 and source.RowNum = 1
    then
        update set target.vchnote = vchnote + CHAR(13) + source.Notes3

但得到错误

MERGE 语句多次尝试更新或删除同一行。当目标行匹配多个源行时会发生这种情况。 MERGE 语句不能多次 UPDATE/DELETE 目标表的同一行。优化 ON 子句以确保目标行最多匹配一个源行,或使用 GROUP BY 子句对源行进行分组。 这是准确的。

我也尝试过STRING_AGG,但得到一个未定义的 UDF 错误。

如何更改我的代码以迭代运行?

--编辑-- 我试过以下更新代码

    WITH CTE
AS (SELECT ROW_NUMBER() OVER (PARTITION BY CompanyName, Notes3 ORDER BY CompanyName) RowNum, *
    FROM CompanyContact
    )
    UPDATE dCompany SET vchNote = vchNote + 
    (select CHAR(13) + cc.Notes3 from CompanyContact cc 
    inner JOIN dCompany dc ON dc.vchCompanyName COLLATE database_default = LEFT(cc.CompanyName,50) COLLATE database_default
    inner join CTE on dc.vchCompanyName COLLATE database_default = LEFT(CTE.CompanyName,50) COLLATE database_default
     WHERE LEN(cc.Notes3)>0
     and RowNum = 1     
     );

但得到错误

子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

【问题讨论】:

  • 当唯一的操作是UPDATE 时,为什么要使用MERGE?为什么不直接更新目标?
  • <first unnamed table> 中似乎没有提供订单的列。
  • 看起来您正在尝试使用第一个表中的 连接 字符串更新第二个表。这不是一个简单的更新,绝对不需要合并。 STRING_AGG 是在 SQL Server 2017 中添加的。如果您不能使用它,则意味着您使用的是旧版本的 SQL Server。您必须为连接字符串创建自定义解决方案。 This article by Aaron Bertrand 解释各种技术及其性能
  • 看起来您尝试使用MERGE 而不是UPDATE 执行quirky updateMERGE 不允许对同一行进行多次修改。如果是这样,您最终会更新您在同一个 MERGE 语句中添加的同一行
  • 更新 可能 工作,但没有指定行的顺序。 ROW_NUBMER() 将返回一个随机顺序,any 字符串连接技术也是如此。除非您使用 ORDER BY 子句指定,否则表行没有顺序

标签: sql-server tsql merge


【解决方案1】:

@Chris Crawshaw,我将通过在源表和目标表上执行“联合所有”来获取每个公司的所有注释来解决此问题。然后使用 STUFF 功能,很容易将所有笔记连接到一个单元格中,同时按个别公司名称进行分组。请参阅下面的模型:

DECLARE @Source TABLE (CompanyName VARCHAR(20), Notes3 VARCHAR(50))
INSERT INTO @Source
SELECT 'Company1', 'spoke with someone' UNION ALL
SELECT 'Company2', 'Email no longer works' UNION ALL
SELECT 'Company1', 'Moved address'

DECLARE @Destination TABLE (vchCompanyName VARCHAR(20), vchNotes VARCHAR(500))
INSERT INTO @Destination
SELECT 'Company1', 'started business in 2005' UNION ALL
SELECT 'Company2', NULL




    ;WITH Temp AS (

    SELECT *
    FROM
    (
        SELECT *
        FROM
            @Destination D
        WHERE D.vchNotes is not null
        UNION ALL
        SELECT * 
        FROM
            @Source S  

    )h


    )

    update  D
    SET D.vchNotes=U.vchNotes

    FROM @Destination D
    LEFT JOIN(
    SELECT t2.vchCompanyName, vchNotes=STUFF((
        SELECT  ',' + vchNotes
        FROM Temp t1 where t1.vchCompanyName=t2.vchCompanyName
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    FROM
        @Destination t2
    GROUP BY
        t2.vchCompanyName
        )U ON
            U.vchCompanyName=D.vchCompanyName


    --TEST--
            SELECT * 
            FROM
            @Destination

【讨论】:

  • 谢谢,这可以作为一个选择,但我正在努力根据返回的vchCompanyName 将其转换为更新。另外,为什么在右括号后面有一个 h?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多