Sql-Server

如何用多行數據替換字元串的多個部分?

  • May 2, 2019

給定一個包含兩列的表 - 一個整數 ID 和一個基於文本的字元串 - 我想從一個字元串值開始,該字元串值對包含在花括號中的任意數量的整數進行編碼,並與任何其他有效的文本字元混合。

例子:'{1} / {9} ... {12}'

使用單個SELECT語句,我想返回一個字元串,其中所有整數(及其包裝大括號)都已替換為從我的表中派生的值;具體來說,具有與源字元串中找到的數字相匹配的 ID 的行的文本值……以及大括號外的任何字元保持不變。

這是一個無法完成任務的範例:

select
 replace('{13} {15}','{'+cast(id as varchar)+'}',isNull(display,''))
from testing;

testing這將在表中每行返回 1 行。對於idvalue = 13 的行,字元串的“{13}”部分已成功替換,但“{15}”部分未成功替換(反之亦然,在第 15 行)。

我想創建一個循環遍歷所有testing行並反复嘗試替換的函式將解決問題。儘管如此,直接的 SQL 語句將比循環更可取。

範例數據

+----+-------------------+
| id |  display          |
+----+-------------------+
|  1 |  Apple            |
|  2 |  Banana           |
|  3 |  Celery           |
|  4 |  Dragonfruit      |
|  5 |  Eggplant         |
|  6 |  Fenugreek        |
|  7 |  Gourd            |
|  8 |  Honeydew         |
|  9 |  Iceberg Lettuce  |
| 10 |  Jackfruit        |
| 11 |  Kale             |
| 12 |  Lemon            |
| 13 |  Mandarin         |
| 14 |  Nectarine        |
| 15 |  Olive            |
+----+-------------------+

範例案例

select replace('{1} {3}',null,null) 
-- Returns 'Apple Celery'

select replace('{3},{4},{5}',null,null); 
-- Returns 'Celery,Dragonfruit,Eggplant'

select replace('{1} / {9} ... {12}',null,null); 
-- Returns 'Apple / Iceberg Lettuce ... Lemon'

顯然,replace關鍵字不起作用。

PS。如果解決方案需要更改字元串的格式以促進這一點,那麼這是一種選擇。

例如:('#1 / #9 ... #12'與前面的範例相關)

在這種格式中,也許我們可以將字元串分解為一個行集,基於#,取left字元直到我們找到一個非數字,根據取的數字join到表中,用表的值testing替換#和 數字然後所有這些單獨將標記修改回單個字元串?testing``display``stuff``for xml path

我正在使用不支持的 SQL Server 2016 string_agg。也就是說,如果有使用 的解決方案string_agg,我仍然有興趣查看它。

這是使用遞歸cte轉換變數的範例

drop table if exists testing;
go
create table testing (id int, display varchar(16));
insert into testing values (1, 'Apple');
insert into testing values (2, 'Banana');
insert into testing values (3, 'Celery');
insert into testing values (4, 'Dragonfruit');
insert into testing values (5, 'Eggplant');

DROP FUNCTION IF EXISTS dbo.TranslateVariables
go
CREATE FUNCTION dbo.TranslateVariables
(
   @StringValue VARCHAR(MAX)
)
RETURNS TABLE

AS
RETURN (

--Common Table Expression for Translation
WITH TranslationTable
AS (
   SELECT FindValue = '{' + convert(varchar(5),id) + '}' ,ReplaceValue = display,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS rn
   FROM testing
   )
--Recursive CTE to loop through the TranslationTable and replace FindValue with ReplaceValue
,RecursiveCte as
(
SELECT @StringValue AS StrValue
   ,(
       SELECT count(*)
       FROM TranslationTable
       ) AS cnt

UNION ALL

SELECT replace(StrValue, tt.FindValue, tt.Replacevalue)
   ,cnt - 1
FROM RecursiveCte
JOIN TranslationTable tt
   ON tt.rn = cnt )

SELECT StrValue
   ,cnt
FROM RecursiveCte where cnt = 0
   )
go

--Verify translation
SELECT *
FROM dbo.TranslateVariables('{1} {3}')
OPTION (MAXRECURSION 32767) -- Don't forget to use the maxrecursion option!

StrValue     | cnt |
|--------------|-----|
| Apple Celery | 0   |

SELECT *
FROM dbo.TranslateVariables('{3},{4},{5}')
OPTION (MAXRECURSION 32767) -- Don't forget to use the maxrecursion option!

| StrValue                    | cnt |
|-----------------------------|-----|
| Celery,Dragonfruit,Eggplant | 0   |

引用自:https://dba.stackexchange.com/questions/237182