MySQL 使用相同的键从多行数据中更新 1 行
MySQL Update 1 row from multiple rows of data with same key
是否可以从另一个 table 更新单个行,而另一个 table 可能有多个具有相同键值的数据行?
数据的快速采样为:
table TA
| ID | Old_Text |
| ---- | ---------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A |
| 1045 | Text_1045B |
| 1050 | Text_1050A |
table TZ (before update)
| ID | New_Text |
| ---- | ---------- |
| 1040 | NULL |
| 1045 | NULL |
| 1050 | NULL |
我正在使用以下更新语句
UPDATE
table TZ
SET
TZ.New_Text =
CASE
WHEN TZ.New_Text IS NULL THEN TA.Old_Text
ELSE TZ.New_Text + ' ' + TA.Old_Text
END
FROM
table TZ INNER JOIN table TA ON TZ.ID = TA.ID
WHERE TZ.ID = TA.ID
并且预期结果应该有 ID 1045 有两个值(Text_1045A Text_1045B),其他的有 1 个。如下所示:
table TZ (after update)
| ID | New_Text |
| ---- | -------------------------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A Text_1045B |
| 1050 | Text_1050A |
相反,我得到了这个:
table TZ (after update)
| ID | New_Text |
| ---- | --------------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A |
| 1050 | Text_1050A |
我做错了什么或不理解我认为更新的工作原理?
一行只更新一次。更新前需要聚合:
UPDATE TZ
SET TZ.New_Text = CONCAT_WS(' ', TZ.New_Text, TA.Old_Text)
FROM table TZ INNER JOIN
(SELECT TA.ID, STRING_AGG(tA.OldText, ' ') as OldText
FROM table TA
GROUP BY TA.ID
) TA
ON TZ.ID = TA.ID;
虽然最佳做法是首先避免重复(通过使用约束)。有时您无法阻止它们。下面我提供了一种获取您描述的输出的方法。
这 SQL 连接相应 ID 的文本和更新。
这也会清除重复记录
SELECT
ID,
(SELECT SUBSTRING(
(SELECT ' ' + s.Old_Text
FROM SampleTable s
WHERE s.ID = sTable.ID
--ORDER BY s.Old_Text
FOR XML PATH('')),2,200000)) [Old_Text]
INTO #Updates
FROM SampleTable sTable
GROUP BY ID
UPDATE s
SET s.Old_Text = u.Old_Text
FROM SampleTable s
INNER JOIN #Updates u
ON s.ID = u.ID
;WITH CTE
AS
(
SELECT ID, Old_Text, ROW_NUMBER() OVER(Partition BY ID ORDER BY ID) [Ranking]
FROM SampleTable
)
DELETE FROM CTE
WHERE Ranking > 1
清除所有重复项后,我强烈建议对该 table 设置一些限制以防止这种情况继续发生。您不希望 运行 无限期地将其作为日常维护。
是否可以从另一个 table 更新单个行,而另一个 table 可能有多个具有相同键值的数据行?
数据的快速采样为:
table TA
| ID | Old_Text |
| ---- | ---------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A |
| 1045 | Text_1045B |
| 1050 | Text_1050A |
table TZ (before update)
| ID | New_Text |
| ---- | ---------- |
| 1040 | NULL |
| 1045 | NULL |
| 1050 | NULL |
我正在使用以下更新语句
UPDATE
table TZ
SET
TZ.New_Text =
CASE
WHEN TZ.New_Text IS NULL THEN TA.Old_Text
ELSE TZ.New_Text + ' ' + TA.Old_Text
END
FROM
table TZ INNER JOIN table TA ON TZ.ID = TA.ID
WHERE TZ.ID = TA.ID
并且预期结果应该有 ID 1045 有两个值(Text_1045A Text_1045B),其他的有 1 个。如下所示:
table TZ (after update)
| ID | New_Text |
| ---- | -------------------------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A Text_1045B |
| 1050 | Text_1050A |
相反,我得到了这个:
table TZ (after update)
| ID | New_Text |
| ---- | --------------- |
| 1040 | Text_1040A |
| 1045 | Text_1045A |
| 1050 | Text_1050A |
我做错了什么或不理解我认为更新的工作原理?
一行只更新一次。更新前需要聚合:
UPDATE TZ
SET TZ.New_Text = CONCAT_WS(' ', TZ.New_Text, TA.Old_Text)
FROM table TZ INNER JOIN
(SELECT TA.ID, STRING_AGG(tA.OldText, ' ') as OldText
FROM table TA
GROUP BY TA.ID
) TA
ON TZ.ID = TA.ID;
虽然最佳做法是首先避免重复(通过使用约束)。有时您无法阻止它们。下面我提供了一种获取您描述的输出的方法。
这 SQL 连接相应 ID 的文本和更新。
这也会清除重复记录
SELECT
ID,
(SELECT SUBSTRING(
(SELECT ' ' + s.Old_Text
FROM SampleTable s
WHERE s.ID = sTable.ID
--ORDER BY s.Old_Text
FOR XML PATH('')),2,200000)) [Old_Text]
INTO #Updates
FROM SampleTable sTable
GROUP BY ID
UPDATE s
SET s.Old_Text = u.Old_Text
FROM SampleTable s
INNER JOIN #Updates u
ON s.ID = u.ID
;WITH CTE
AS
(
SELECT ID, Old_Text, ROW_NUMBER() OVER(Partition BY ID ORDER BY ID) [Ranking]
FROM SampleTable
)
DELETE FROM CTE
WHERE Ranking > 1
清除所有重复项后,我强烈建议对该 table 设置一些限制以防止这种情况继续发生。您不希望 运行 无限期地将其作为日常维护。