Sql server 如何正确替换一行中多次使用的预定义分隔符

Sql server 如何正确替换一行中多次使用的预定义分隔符,sql-server,tsql,Sql Server,Tsql,我有一个保存纯文本的列,并使用分隔符将第一个表中base64中的图像替换为由几个唯一字符和base64表ID组成的分隔符 例如: 表 备注栏 一张图片就在这里,然后是一些文本和另一张图片,这是结尾 每个实例可以返回多个结果。带有1个分隔符的行可以正常工作。这里的问题是,当我尝试根据整个页面选择要显示的具有多个分隔符的分隔符时,它将显示类似这样的内容,其中显示为多行 这里有一张图片数据:image/png;base64。。。这是一些文字和另一张图片,这是结尾 图片就在这里,然后是一些文本和另一个图

我有一个保存纯文本的列,并使用分隔符将第一个表中base64中的图像替换为由几个唯一字符和base64表ID组成的分隔符

例如:

备注栏

一张图片就在这里,然后是一些文本和另一张图片,这是结尾

每个实例可以返回多个结果。带有1个分隔符的行可以正常工作。这里的问题是,当我尝试根据整个页面选择要显示的具有多个分隔符的分隔符时,它将显示类似这样的内容,其中显示为多行

这里有一张图片数据:image/png;base64。。。这是一些文字和另一张图片,这是结尾

图片就在这里,然后是一些文本和另一个图片数据:image/png;base64。。。结束了

我的一般疑问是

 SELECT REPLACE(A.notesColumn,'<##'+CAST(B.base64ID AS VARCHAR(25))+'##>', B.docImage) [noteText]
 FROM tableA A
    LEFT JOIN base64Table B ON A.ID = B.tableANote
 WHERE pageID = @pageID

如何解决显示为多个结果而仅显示一行的问题,无论有多少分隔符?

您都可以通过使用字符串拆分函数将原始文本拆分为组成词,然后在需要时将其加入Base64表以获取相关的替换值,然后根据SQL Server是pre还是pre,通过FOR XML或string_AGG进行重新组合2017年后

如果您使用的是SQL Server 2016或更高版本,您也可以使用STRING_SPLIT,如果不是,您可以使用此答案末尾的函数,这是我的修改版

再看看您的问题,您可能需要一个可以处理4000多个字符的字符串拆分器。如果是这种情况,您可以使用此版本,尽管它在较小字符串上的性能可能比4k版本差:

create function dbo.fn_StringSplitMax
(
    @str nvarchar(max) = ' '                -- String to split.
    ,@delimiter as nvarchar(max) = ','      -- Delimiting value to split on.
    ,@num as int = null                     -- Which value to return.
)
returns table
as
return
    with s as
    (       -- Convert the string to an XML value, replacing the delimiter with XML tags
        select convert(xml,'<x>' + replace((select @str for xml path('')),@delimiter,'</x><x>') + '</x>').query('.') as s
    )
    select rn
          ,item     -- Select the values from the generated XML value by CROSS APPLYing to the XML nodes
    from(select row_number() over (order by (select null)) as rn
              ,n.x.value('.','nvarchar(max)') as item
        from s
              cross apply s.nodes('x') as n(x)
        ) a
    where rn = @num
        or @num is null;

这是一个罕见的时刻,一个古怪的更新可以帮助很多:

@iamdave的信用卡,使用了部分mcve

CREATE TABLE B(id int,p varchar(100));
insert into B values(1,'THIS IS PICTURE 1'),(2,'THIS IS PICTURE 2'),(3,'THIS IS PICTURE 3');
GO

CREATE TABLE A(v varchar(500));
insert into A values('A picture is right here <##1##> and then here is some text and another picture <##2##> and here is the end')
                   ,('Another picture is here <##1##> and yet more text and another picture <##2##> and here is the end')
                   ,('Another example with a picutre <##2##> here and one more here <##3##>');
GO
-清理:小心真实数据

DROP FUNCTION dbo.MultipleImageReplace;
GO
DROP TABLE B;
GO
DROP TABLE A;
DROP TABLE B;
GO
DROP TABLE A;
结果

A picture is right here THIS IS PICTURE 1 and then here is some text and another picture THIS IS PICTURE 2 and here is the end
Another picture is here THIS IS PICTURE 1 and yet more text and another picture THIS IS PICTURE 2 and here is the end
Another example with a picutre THIS IS PICTURE 2 here and one more here THIS IS PICTURE 3
神奇古怪更新的一些背景:

该函数使用@input=Modify@input. 这将导致一个逐行操作,表B的每一行都将修改@input的内容并将其重新分配给变量。因此,下一行将处理修改后的内容,依此类推


这种方法有一些严重的缺点,一般不推荐使用。但在这种情况下,排序并不重要,你可以试一试。

我将此作为第二个答案,因为方法与另一个完全不同,我不想混淆这一点

您可以使用XQuery及其强大的功能来处理通用数据

测试场景:

CREATE TABLE B(id int,p varchar(100));
insert into B values(1,'THIS IS PICTURE 1'),(2,'THIS IS PICTURE 2'),(3,'THIS IS PICTURE 3');
GO

CREATE TABLE A(v varchar(500));
insert into A values('A picture is right here <##1##> and then here is some text and another picture <##2##> and here is the end')
                   ,('Another picture is here <##1##> and yet more text and another picture <##2##> and here is the end')
                   ,('Another example with a picutre <##2##> here and one more here <##3##>');
GO
一个经过转换的XML如下所示:

<root>
  <row>
    <text>Another example with a picutre </text>
    <img index="2" />
    <text> here and one more here </text>
    <img index="3" />
    <text />
  </row>
  <images>
    <img>
      <id>1</id>
      <p>THIS IS PICTURE 1</p>
    </img>
    <img>
      <id>2</id>
      <p>THIS IS PICTURE 2</p>
    </img>
    <img>
      <id>3</id>
      <p>THIS IS PICTURE 3</p>
    </img>
  </images>
</root>

是一个很好的起点。请与我们共享tableB的内容。@donPablo如果您引用的是Base64表,则内容为ID、tableAID FK、docImage VARCHARMAXNo,仅列出列是无用的。没有人能对此提出质疑。我们需要基于您的示例数据获得表定义、示例数据和所需输出。我怀疑这可以通过使用Quirk更新来实现,但没有进一步的信息,我无法确认。您的函数fn_StringSplit4k在哪里?
DROP FUNCTION dbo.MultipleImageReplace;
GO
DROP TABLE B;
GO
DROP TABLE A;
A picture is right here THIS IS PICTURE 1 and then here is some text and another picture THIS IS PICTURE 2 and here is the end
Another picture is here THIS IS PICTURE 1 and yet more text and another picture THIS IS PICTURE 2 and here is the end
Another example with a picutre THIS IS PICTURE 2 here and one more here THIS IS PICTURE 3
CREATE TABLE B(id int,p varchar(100));
insert into B values(1,'THIS IS PICTURE 1'),(2,'THIS IS PICTURE 2'),(3,'THIS IS PICTURE 3');
GO

CREATE TABLE A(v varchar(500));
insert into A values('A picture is right here <##1##> and then here is some text and another picture <##2##> and here is the end')
                   ,('Another picture is here <##1##> and yet more text and another picture <##2##> and here is the end')
                   ,('Another example with a picutre <##2##> here and one more here <##3##>');
GO
WITH Casted AS
(
    SELECT *
          ,CAST('<root>
                 <row>
                   <text>' + REPLACE(REPLACE(A.v,'<##','</text><img index="'),'##>','"/><text>') + '</text>
                 </row>
                 <images>' +

                 --and we will include the pictures to be part of the XML
                 --this will make it easier to use them in the XQuery
                 --You might use two CTEs to include just the pictures needed
                 (
                    SELECT *
                    FROM B
                    FOR XML PATH('img')
                 ) + 
                 '</images>
                 </root>
                 ' AS XML) AS CastedToXml
    FROM A
)
--We use a simple "for .. in .." loop to travers down the nodes and return their content "as-is" or replaced by the corresponding image
SELECT CastedToXml.query('for $nd in /root/row/*
                          return
                          if(local-name($nd)="img") then 
                              /root/images/img[id=$nd/@index]/p/text()
                          else 
                              $nd/text()
                         ').value('.','nvarchar(max)')
FROM Casted
GO
DROP TABLE B;
GO
DROP TABLE A;
<root>
  <row>
    <text>Another example with a picutre </text>
    <img index="2" />
    <text> here and one more here </text>
    <img index="3" />
    <text />
  </row>
  <images>
    <img>
      <id>1</id>
      <p>THIS IS PICTURE 1</p>
    </img>
    <img>
      <id>2</id>
      <p>THIS IS PICTURE 2</p>
    </img>
    <img>
      <id>3</id>
      <p>THIS IS PICTURE 3</p>
    </img>
  </images>
</root>
A picture is right here THIS IS PICTURE 1 and then here is some text and another picture THIS IS PICTURE 2 and here is the end
Another picture is here THIS IS PICTURE 1 and yet more text and another picture THIS IS PICTURE 2 and here is the end
Another example with a picutre THIS IS PICTURE 2 here and one more here THIS IS PICTURE 3