場景:Email20140725 表含重複郵件記錄,需依 Email, OrderNo, TrackingNo 分組,將同群組的 OrderNo、TrackingNo 以「、」串聯合併為單筆。
CREATE PROCEDURE HandleEmailRepeat
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Email VARCHAR(200), @OrderNo VARCHAR(300), @TrackingNo VARCHAR(300);
DECLARE @PrevEmail VARCHAR(200), @PrevOrderNo VARCHAR(300), @PrevTrackingNo VARCHAR(300);
DECLARE @MergedOrderNo VARCHAR(MAX), @MergedTrackingNo VARCHAR(MAX);
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT Email, OrderNo, TrackingNo
FROM Email20140725
WHERE [Status] = 0
ORDER BY Email, OrderNo, TrackingNo;
OPEN cur;
FETCH NEXT FROM cur INTO @Email, @OrderNo, @TrackingNo;
-- 初始化第一筆
SET @PrevEmail = @Email;
SET @MergedOrderNo = @OrderNo;
SET @MergedTrackingNo = @TrackingNo;
FETCH NEXT FROM cur INTO @Email, @OrderNo, @TrackingNo;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @Email = @PrevEmail
BEGIN
-- 同群組:累加串聯
IF @OrderNo NOT LIKE '%' + @MergedOrderNo + '%' -- 簡易去重
SET @MergedOrderNo += '、' + @OrderNo;
IF @TrackingNo NOT LIKE '%' + @MergedTrackingNo + '%'
SET @MergedTrackingNo += '、' + @TrackingNo;
END
ELSE
BEGIN
-- 群組切換:寫入結果表
INSERT INTO Email20140725Test (Email, OrderNo, TrackingNo)
VALUES (@PrevEmail, @MergedOrderNo, @MergedTrackingNo);
-- 重置為新群組
SET @PrevEmail = @Email;
SET @MergedOrderNo = @OrderNo;
SET @MergedTrackingNo = @TrackingNo;
END
FETCH NEXT FROM cur INTO @Email, @OrderNo, @TrackingNo;
END
-- 寫入最後一組
INSERT INTO Email20140725Test (Email, OrderNo, TrackingNo)
VALUES (@PrevEmail, @MergedOrderNo, @MergedTrackingNo);
CLOSE cur; DEALLOCATE cur;
END
INSERT INTO Email20140725Test (Email, OrderNo, TrackingNo)
SELECT
Email,
STRING_AGG(OrderNo, '、') WITHIN GROUP (ORDER BY OrderNo) AS OrderNo,
STRING_AGG(TrackingNo, '、') WITHIN GROUP (ORDER BY TrackingNo) AS TrackingNo
FROM Email20140725
WHERE [Status] = 0
GROUP BY Email;
INSERT INTO Email20140725Test (Email, OrderNo, TrackingNo)
SELECT
Email,
STUFF((SELECT '、' + OrderNo FROM Email20140725 t2 WHERE t2.Email = t1.Email FOR XML PATH('')), 1, 1, '') AS OrderNo,
STUFF((SELECT '、' + TrackingNo FROM Email20140725 t2 WHERE t2.Email = t1.Email FOR XML PATH('')), 1, 1, '') AS TrackingNo
FROM Email20140725 t1
WHERE [Status] = 0
GROUP BY Email;
| 方法 | 適用版本 | 效能 | 可維護性 |
|---|---|---|---|
| 游標 | 所有版本 | 低 (RBAR) | 邏輯直觀但冗長 |
| FOR XML PATH | 2005+ | 中 | 技巧性強 |
| STRING_AGG | 2017+ | 高 (原生優化) | 語法簡潔標準 |
建議:現代版本優先用 STRING_AGG,舊版用 FOR XML PATH,避免游標。僅當邏輯極其複雜 (跨表、多階段、程序性) 才考慮游標。