【问题标题】:How to use 'Merge' to combine rows into a single one如何使用“合并”将行合并为一个
【发布时间】:2016-08-09 07:38:48
【问题描述】:

场景: 我有一个从一系列复杂连接中获得的结果集的简化版本。我已将结果集放在一个临时表中。结果集由一天中的活动记录组成。

我需要加入具有相似日期的 2 行(将一天的活动合并为一行),以便生成的结果集是

我正在努力完成这项工作

Merge #temp as target
using #temp as source
on (target.Date = source.Date) and target.Writing is NULL
when matched then
update set target.Writing = source.Writing;

但我遇到了这个错误:

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

您可以建议哪些代码修改?

【问题讨论】:

  • 想要的结果从何而来? (d,d,d,null),(e,e,null,e)怎么会被折叠成(d,e,d,e)
  • 听起来您正在将流程分解为一系列 过程 步骤,并在优化数据时使用临时表作为某种形式的“临时空间”放。尽管您可以这样做,但理想情况下您不要将此类过程分解为一系列步骤。您使用 CTE 和/或子查询来描述您想要的整个结果,这样整个事情就是一个(大)查询,然后让优化器找出如何最好地产生这个结果。 IE。让 SQL 做它擅长的事情,使用集合。
  • @MartinSmith,所需的结果来自连接在一起的各种表。 Col1 = 进入时间,Col 2 = 超时,Col 3 = 活动 1,Col 4 = 活动 2。一天中的所有活动应仅反映在一行中
  • 更新您的问题,使其清晰并包含所有必要信息。评论可能会消失。
  • 为什么Col 1 选择d 而不是e,其中Date08-04,为什么e 选择e 而不是e 选择Col 2同一行?

标签: sql-server merge


【解决方案1】:

应该这样做:

    SELECT dfl.mydate, dfl.firststart, dfl.lastend, fa.ActivityA, sa.ActivityB 
    FROM
    (select s.mydate, firststart, lastend FROM
    (SELECT mydate, MIN(starttime) as firststart from target GROUP by mydate) s
    iNNER JOIN
    (SELECT mydate, MAX(EndTime) as lastend from target GROUP by mydate) e
    ON s.mydate = e.mydate) AS dfl
    INNER JOIN
    target fa on dfl.mydate = fa.mydate and dfl.firststart = fa.starttime
    INNER JOIN
    target sa on dfl.mydate = sa.mydate and dfl.lastend = sa.EndTime

请注意,对于我的测试,我已经调用了我的表目标和列:mydate、starttime、endtime、activitya 和 activityb。

无需合并,(相对)简单的选择会产生您想要的结果。

HTH

PS 在使用时间数据时使用 24 小时制时钟会有所帮助。我假设到 5:00 你真的是指 17:00

【讨论】:

    【解决方案2】:

    你不需要 MERGE 语句。

    DECLARE @Test TABLE ([Id] int, [Date] nvarchar(10), [TimeIn] nvarchar(10), [TimeOut] nvarchar(10), [Reading] nvarchar(10), [Writeing] nvarchar(10))
    INSERT INTO @Test 
    VALUES
    (1,'08-01','8:00','5:00','Y',NULL),
    (2,'08-02','8:00','5:00',NULL,'Y'),
    (3,'08-02','5:00','12:00',NULL,'Y'),
    (4,'08-03','8:00','5:00',NULL,'Y'),
    (5,'08-04','1:00','5:00','Y',NULL),
    (6,'08-04','5:00','7:00',NULL,'Y'),
    (7,'08-04','7:00','10:00',NULL,'Y'),
    (8,'08-04','10:00','13:00',NULL,'Y'),
    (9,'08-05','8:00','5:00','Y',NULL)
    
    ;WITH CTE AS
    (
        SELECT 
            t1.[Date],
            t1.TimeIn,
            ISNULL(t2.TimeOut, t1.TimeOut) AS TimeOut,
            ROW_NUMBER() OVER (PARTITION BY t1.[Date] ORDER BY t1.Id) AS RowNumber
        FROM @Test AS t1
        LEFT OUTER JOIN @Test AS t2 ON t1.TimeOut = t2.TimeIn AND t1.[Date] = t2.[Date]
    )
    SELECT
        c.[Date],
        (SELECT c2.TimeIn FROM CTE AS c2 WHERE c2.[Date] = c.[Date] AND c2.RowNumber = MIN(c.RowNumber)) AS TimeIn,
        (SELECT c2.TimeOut FROM CTE AS c2 WHERE c2.[Date] = c.[Date] AND c2.RowNumber = MAX(c.RowNumber)) AS TimeOut
    FROM CTE AS c
    GROUP BY c.[Date]
    

    【讨论】:

      【解决方案3】:

      您可以在具有相同列的表中使用合并语句。您可以识别一列或多列可用于唯一标识要合并的行。

      【讨论】:

        猜你喜欢
        • 2011-11-24
        • 1970-01-01
        • 2022-08-17
        • 1970-01-01
        • 2020-06-24
        • 1970-01-01
        • 2021-08-06
        • 1970-01-01
        相关资源
        最近更新 更多