給定兩張表:
(ID, Word)(ID, original_id, similar_id),雙向儲存(如 101↔102、103↔105、104↔105)需求:輸出每個單字及其所有形近詞,形近詞以逗號分隔合併為單一欄位。
| originalword.ID | orig_word | similar_Word |
|---|---|---|
| 101 | about | abound |
| 102 | abound | about |
| 103 | beard | beast |
| 104 | boast | beast |
| 105 | beast | beard,boast |
CREATE FUNCTION dbo.f_hb(@original_id VARCHAR(10))
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @str VARCHAR(8000) = '';
SELECT @str = @str + ',' + b.Word
FROM similarword a
INNER JOIN originalWord b ON a.similar_id = b.ID
WHERE a.original_id = @original_id;
RETURN STUFF(@str, 1, 1, ''); -- 移除首個逗號
END;
GO
-- 調用
SELECT DISTINCT
a.original_id AS [originalword.ID],
b.Word AS orig_Word,
dbo.f_hb(a.original_id) AS similar_id
FROM similarword a
INNER JOIN originalWord b ON a.original_id = b.ID;
優點:語法簡潔、易維護。
缺點:逐行呼叫函數,大量資料時效能較差(RBAR 模式)。
DECLARE @Result TABLE(
id INT IDENTITY(1,1),
[originalword.ID] INT,
orig_word NVARCHAR(30),
similar_Word NVARCHAR(30)
);
INSERT INTO @Result ([originalword.ID], orig_word)
SELECT ID, Word FROM originalWord;
DECLARE @i INT = 1, @j INT = (SELECT COUNT(*) FROM @Result),
@similar_Word NVARCHAR(200);
WHILE @i <= @j
BEGIN
SET @similar_Word = '';
SELECT @similar_Word = @similar_Word + Word + ','
FROM (
SELECT B.Word
FROM similarword A
INNER JOIN originalWord B ON A.similar_id = B.ID
WHERE EXISTS (
SELECT 1 FROM @Result C
WHERE C.[originalword.ID] = A.original_id
AND C.id = @i
)
) Tmp;
IF @similar_Word <> ''
UPDATE @Result
SET similar_Word = SUBSTRING(@similar_Word, 1, LEN(@similar_Word)-1)
WHERE id = @i;
SET @i = @i + 1;
END
SELECT [originalword.ID], orig_word, similar_Word FROM @Result;
優點:避免函數呼叫開銷,批次處理。
缺點:程序式寫法,可讀性較低;仍屬逐行處理。
SELECT
ow.ID AS [originalword.ID],
ow.Word AS orig_word,
STRING_AGG(sw.Word, ',') WITHIN GROUP (ORDER BY sw.Word) AS similar_Word
FROM originalWord ow
LEFT JOIN similarWord sw_link ON ow.ID = sw_link.original_id
LEFT JOIN originalWord sw ON sw_link.similar_id = sw.ID
GROUP BY ow.ID, ow.Word
ORDER BY ow.ID;
優點:宣告式、單一掃描、效能最佳、可攜性強(PostgreSQL/MySQL 亦支援 STRING_AGG / GROUP_CONCAT)。
| 方案 | 適用版本 | 資料量<1萬 | 資料量>10萬 | 維護性 |
|---|---|---|---|---|
| UDF | All | 可接受 | 慢(CPU 高) | 高 |
| WHILE 迴圈 | All | 尚可 | 中等 | 中 |
| STRING_AGG | 2017+ | 極快 | 極快 | 最高 |
建議:優先使用 STRING_AGG(或 FOR XML PATH 相容舊版);僅在不支援聚合函數的舊版本(≤2014)才考慮 UDF 或迴圈。