Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何使用SQL Server 2016中另一个表中的值替换长字符串中的模式子字符串_Sql Server_Pattern Matching - Fatal编程技术网

Sql server 如何使用SQL Server 2016中另一个表中的值替换长字符串中的模式子字符串

Sql server 如何使用SQL Server 2016中另一个表中的值替换长字符串中的模式子字符串,sql-server,pattern-matching,Sql Server,Pattern Matching,我在SQL Server 2016中遇到了替换函数的问题,我无法用任何模式替换。问题是: 我有一个大字符串,里面有两个查询,它们之间用@@@模式分隔,如下所示: 我有个问题@@你叫什么名字@@@你多大了@@@我需要 更多答案。@@您好@。如果您愿意,请回答 现在,@@@中的文本是一个查询。此查询的答案保存在另一个数据库表中 我想用表值替换文本中的查询。我们可以从表中运行游标来获取值,然后替换为特定位置。假设我们在表格(答案)中有如下查询值,我们可以按照查询顺序获取数据: 你叫什么名字 你多大年

我在SQL Server 2016中遇到了替换函数的问题,我无法用任何模式替换。问题是:

我有一个大字符串,里面有两个查询,它们之间用@@@模式分隔,如下所示:

我有个问题@@你叫什么名字@@@你多大了@@@我需要 更多答案。@@您好@。如果您愿意,请回答

现在,@@@中的文本是一个查询。此查询的答案保存在另一个数据库表中

我想用表值替换文本中的查询。我们可以从表中运行游标来获取值,然后替换为特定位置。假设我们在表格(答案)中有如下查询值,我们可以按照查询顺序获取数据:

  • 你叫什么名字
  • 你多大年纪->29岁
  • 你好吗->我很好
最后的答案是:我有一个问题Doe29我需要更多的答案。我很好。如果你想回答的话

现在,我发现在SQL Server 2016中替换两个查询之间的每个查询都有困难


是否有人可以帮助我了解在哪一个SQL Server函数上可以获得按模式替换的功能,并使用表中的原始值替换查询?

必须存在使用SQL游标的解决方案,但此问题不需要该解决方案。下面的解决方案使用两个(递归CTE)和一些。完整的解决方案似乎令人望而生畏,因此我将其背后的方法分为三个步骤

样本数据

declare @question table
(
    question nvarchar(200) primary key clustered
);

insert into @question (question) values
('I have a question. @@What is your name@@@@what is your age@@I need more answers.@@How are you@@.Answer if you want.');

declare @answers table
(
    key_ nvarchar(30) primary key clustered,
    value_ nvarchar(30)
);

insert into @answers (key_, value_) values
('What is your name', 'Doe'),
('what is your age', '29'),
('How are you', 'I am fine');
-- 1. Sample Data
SET NOCOUNT ON;
IF OBJECT_ID('dbo.question','U') IS NOT NULL DROP TABLE dbo.question;
IF OBJECT_ID('dbo.answers','U')  IS NOT NULL DROP TABLE dbo.answers;
CREATE TABLE dbo.question
(
  qID      int  PRIMARY KEY CLUSTERED,
  question nvarchar(200) NOT NULL
);
CREATE TABLE dbo.answers
(
  aID    int          NOT NULL INDEX nc__answers__aID,
  key_   nvarchar(30) NOT NULL,
  value_ nvarchar(30) NOT NULL
);
insert into dbo.question (qID,question) values
(1,'I have a question. @@What is your name@@@@what is your age@@I need more answers.'+
   '@@@@@@@@@@@@@@@@@@@How are you@@@@@@@@@@@@@@@@@@@@@@@@@@@.Answer if you want.'),
(2,'I have a question too.@@@@@@@@@@@@Your Name is?@@@how young are you?@@Answer This-'+
   '@@@@@@@@@@@You good?@@@@@@@@@@@@@@@How is Bill@@@@@@@@Answer if you must!.');
insert into dbo.answers (aID,key_, value_) values
(1,'What is your name','Doe'),(1,'what is your age','29'),(1,'How are you','I am fine'),
(2,'Your Name is?','Fred'),(2,'how young are you?','38'),(2,'Answer This-','What?'),
(2,'You good?','Yeah!'),(2,'How is Bill','Sleepy');

-- 2. Add Many New rows for performance testing
DECLARE @multiplier BIGINT = 10000;

INSERT dbo.question
SELECT     ROW_NUMBER() OVER (ORDER BY (SELECT NULL))+2, q.question
FROM       dbo.question                    AS q
CROSS JOIN core.rangeAB(1,@multiplier,1,1) AS r;

INSERT     dbo.answers
SELECT     a.aID%2+((a.aID+r.RN)*2), a.key_, a.value_
FROM       dbo.answers                     AS a
CROSS JOIN core.rangeAB(1,@multiplier,1,0) AS r;
完整解决方案

with cte_position as
(
    select  charindex('@@', q.question, 0) as 'position',
            1 as 'count_',
            convert(nvarchar(30), null) as 'key_',
            q.question
    from @question q
        union all
    select  charindex('@@', cp.question, cp.position+2),
            cp.count_+1,
            convert(nvarchar(30), case
                when (cp.count_+1) % 2 = 0
                then substring(cp.question, cp.position+2, charindex('@@', cp.question, cp.position+2)-cp.position-2)
                else null
            end),
            cp.question
    from cte_position cp
    where charindex('@@', cp.question, cp.position+2) > 0
),
cte_replace as
(
    select  cp.count_,
            cp.key_,
            replace(cp.question, '@@'+cp.key_+'@@', a.value_) as 'newquestion'
    from cte_position cp
    join @answers a
        on a.key_ = cp.key_
    where cp.key_ is not null
      and not exists (  select top 1 'x'
                        from cte_position cp2
                        where cp2.key_ is not null
                          and cp2.count_ < cp.count_ )
        union all
    select  cp.count_,
            cp.key_,
            replace(cr.newquestion, '@@'+cp.key_+'@@', a.value_)
    from cte_replace cr
    join cte_position cp
        on cp.count_ = cr.count_ + 2
    join @answers a
        on a.key_ = cp.key_
)
select top 1 cr.newquestion
from cte_replace cr
order by cr.count_ desc;
第2部分-用值替换键

重复CTE的结构
CTE\u replace

  • 仅选择具有要替换的键的中间记录=
    cp.key\uu.不为空
  • 以计数最低的第一条记录为例(因此计数较低的记录必须不存在)
  • 选择计数器
  • 选择要替换的键
  • 加入
    @answer
    执行实际操作,并将结果重命名为
    newquestion
  • 对于递归部分:

  • 采用之前的记录(上述步骤1至5)
  • 通过加入
    cte_positions
    并使用大于2的
    count_
    对记录进行过滤(我们在步骤1中仅选择偶数行),获得下一个键
  • 加入
    @answer
    执行实际的更换操作
  • 当在
    @answer
    中找不到更多要替换的
    键时,递归停止
  • 中间结果

    第3部分-选择最终结果

    newquestion
    -----------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    -- 3. Performance Test
    BEGIN
      PRINT CHAR(10)+'Start Test'+CHAR(10)+REPLICATE('-',90);
        IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
        IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2;
        IF OBJECT_ID('tempdb..#t3') IS NOT NULL DROP TABLE #t3;
        IF OBJECT_ID('tempdb..#t4') IS NOT NULL DROP TABLE #t4;
      
      PRINT CHAR(10)+'delimitedSplit8K serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t1
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'delimitedSplit8K parallel'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t2
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
      
      PRINT CHAR(10)+'patExtract8K Serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t3
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'patExtract8K Parallel'+CHAR(10)+REPLICATE('-',90);
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t4
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
    END
    
    最简单的部分:从最后一个计数最高的结果集中选择记录,以便在按计数递减排序时第一个(
    top 1
    )记录(
    cr.count\uu desc

    结果

    newquestion
    -----------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    -- 3. Performance Test
    BEGIN
      PRINT CHAR(10)+'Start Test'+CHAR(10)+REPLICATE('-',90);
        IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
        IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2;
        IF OBJECT_ID('tempdb..#t3') IS NOT NULL DROP TABLE #t3;
        IF OBJECT_ID('tempdb..#t4') IS NOT NULL DROP TABLE #t4;
      
      PRINT CHAR(10)+'delimitedSplit8K serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t1
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'delimitedSplit8K parallel'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t2
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
      
      PRINT CHAR(10)+'patExtract8K Serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t3
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'patExtract8K Parallel'+CHAR(10)+REPLICATE('-',90);
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t4
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
    END
    

    更新20200725

    不需要游标、循环或递归CTE。游标或递归解决方案几乎肯定是缓慢且过于庞大的。一个基于集合的解决方案,利用或使用是最好的选择

    注意更新的样本数据(包括更多@):

    每个解决方案的结果:

    FinalAnswer
    --------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    delimitedSplit8K serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7641 ms,  elapsed time = 7643 ms.
    
    delimitedSplit8K parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 12454 ms,  elapsed time = 2118 ms.
    
    patExtract8K Serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 4172 ms,  elapsed time = 4216 ms.
    
    patExtract8K Parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7453 ms,  elapsed time = 1343 ms.
    
    与方法相比,提取器方法的优点是该方法“跳过”分隔符(@)。比较执行计划:

    DSPLIT8K执行计划

    patExtract8K执行计划

    我在示例数据中添加了一些额外的分隔符,以显示它如何使用提取器提取6个必需项,并开始只向前处理6行(而不是55行)

    注意,在本例中,我们只处理一条记录。为了更好地理解如何对多行执行此操作,您需要有更好的示例数据

    最终编辑20200726(性能测试):

    FinalAnswer
    --------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    delimitedSplit8K serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7641 ms,  elapsed time = 7643 ms.
    
    delimitedSplit8K parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 12454 ms,  elapsed time = 2118 ms.
    
    patExtract8K Serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 4172 ms,  elapsed time = 4216 ms.
    
    patExtract8K Parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7453 ms,  elapsed time = 1343 ms.
    
    基于此线程中的讨论。我包括了两个不同的拆分器,可以用于此目的,并利用串行和并行执行计划对它们进行了测试

    样本数据

    declare @question table
    (
        question nvarchar(200) primary key clustered
    );
    
    insert into @question (question) values
    ('I have a question. @@What is your name@@@@what is your age@@I need more answers.@@How are you@@.Answer if you want.');
    
    declare @answers table
    (
        key_ nvarchar(30) primary key clustered,
        value_ nvarchar(30)
    );
    
    insert into @answers (key_, value_) values
    ('What is your name', 'Doe'),
    ('what is your age', '29'),
    ('How are you', 'I am fine');
    
    -- 1. Sample Data
    SET NOCOUNT ON;
    IF OBJECT_ID('dbo.question','U') IS NOT NULL DROP TABLE dbo.question;
    IF OBJECT_ID('dbo.answers','U')  IS NOT NULL DROP TABLE dbo.answers;
    CREATE TABLE dbo.question
    (
      qID      int  PRIMARY KEY CLUSTERED,
      question nvarchar(200) NOT NULL
    );
    CREATE TABLE dbo.answers
    (
      aID    int          NOT NULL INDEX nc__answers__aID,
      key_   nvarchar(30) NOT NULL,
      value_ nvarchar(30) NOT NULL
    );
    insert into dbo.question (qID,question) values
    (1,'I have a question. @@What is your name@@@@what is your age@@I need more answers.'+
       '@@@@@@@@@@@@@@@@@@@How are you@@@@@@@@@@@@@@@@@@@@@@@@@@@.Answer if you want.'),
    (2,'I have a question too.@@@@@@@@@@@@Your Name is?@@@how young are you?@@Answer This-'+
       '@@@@@@@@@@@You good?@@@@@@@@@@@@@@@How is Bill@@@@@@@@Answer if you must!.');
    insert into dbo.answers (aID,key_, value_) values
    (1,'What is your name','Doe'),(1,'what is your age','29'),(1,'How are you','I am fine'),
    (2,'Your Name is?','Fred'),(2,'how young are you?','38'),(2,'Answer This-','What?'),
    (2,'You good?','Yeah!'),(2,'How is Bill','Sleepy');
    
    -- 2. Add Many New rows for performance testing
    DECLARE @multiplier BIGINT = 10000;
    
    INSERT dbo.question
    SELECT     ROW_NUMBER() OVER (ORDER BY (SELECT NULL))+2, q.question
    FROM       dbo.question                    AS q
    CROSS JOIN core.rangeAB(1,@multiplier,1,1) AS r;
    
    INSERT     dbo.answers
    SELECT     a.aID%2+((a.aID+r.RN)*2), a.key_, a.value_
    FROM       dbo.answers                     AS a
    CROSS JOIN core.rangeAB(1,@multiplier,1,0) AS r;
    
    性能测试

    newquestion
    -----------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    -- 3. Performance Test
    BEGIN
      PRINT CHAR(10)+'Start Test'+CHAR(10)+REPLICATE('-',90);
        IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
        IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2;
        IF OBJECT_ID('tempdb..#t3') IS NOT NULL DROP TABLE #t3;
        IF OBJECT_ID('tempdb..#t4') IS NOT NULL DROP TABLE #t4;
      
      PRINT CHAR(10)+'delimitedSplit8K serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t1
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'delimitedSplit8K parallel'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t2
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY dbo.delimitedSplit8K(q.question,'@')                     AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID  = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
      
      PRINT CHAR(10)+'patExtract8K Serial'+CHAR(10)+REPLICATE('-',90);
      
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t3
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (MAXDOP 1);
      
      PRINT CHAR(10)+'patExtract8K Parallel'+CHAR(10)+REPLICATE('-',90);
      WITH q2 AS (SELECT q.qID FROM dbo.question AS q GROUP BY q.qID)
      SELECT
        q2.qID,
        FinalAnswer = fa.FinalAnswer
      INTO   #t4
      FROM   q2
      CROSS APPLY
      (
        SELECT      ISNULL(a.value_,split.item)
        FROM        (SELECT q.* FROM dbo.question AS q WHERE q.qID = q2.qID) AS q
        CROSS APPLY samd.patExtract8K(q.question,'@')                        AS split
        LEFT JOIN   (SELECT a.* FROM dbo.answers  AS a WHERE a.aID = q2.qID) AS a
          ON        a.aID = q.qID
          AND       a.key_ = split.item
        ORDER BY    split.ItemNumber
        FOR XML PATH('')
      ) AS fa(FinalAnswer)
      OPTION (QUERYTRACEON 8649);
    END
    
    结果:

    FinalAnswer
    --------------------------------------------------------------------------
    I have a question. Doe29I need more answers.I am fine.Answer if you want.
    
    delimitedSplit8K serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7641 ms,  elapsed time = 7643 ms.
    
    delimitedSplit8K parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 12454 ms,  elapsed time = 2118 ms.
    
    patExtract8K Serial
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 4172 ms,  elapsed time = 4216 ms.
    
    patExtract8K Parallel
    ------------------------------------------------------------------------------------------
     SQL Server Execution Times: CPU time = 7453 ms,  elapsed time = 1343 ms.
    

    为此,需要一个基于集合的解决方案。Patextract在这里工作是因为有超长的分隔符。我尝试了下面的递归CTE解决方案,但无法使其工作;部分原因是,逻辑需要活在一个比我有时间做的工作更多的函数中。尽管如此,对于(大多数情况下。)

    准备充分的答案,做得好。然而,递归会很慢,而且对于这种类型的事情来说有点复杂。性能完全取决于数据集的大小和复杂性以及可用的系统资源。如果没有更多的样本数据,很难验证。我没有为我的解决方案考虑预定义函数。@ AalbBistin对单行样本数据做了一些快速测试。如果我像您一样使用
    主键(解决方案更新)定义表变量,那么我的查询计划的成本(00547064)大约是
    delimitedSplit8K
    解决方案(00253554)的两倍。所以,如果函数是一个选项,那么您的解决方案将是首选方法。说得清楚,我喜欢您的解决方案,在某些方面,我喜欢递归CTES。我在上面添加了一个性能测试线束。我将不得不把你的逻辑转换成一个比计划的更耗时的函数。我怀疑rCTE解决方案会更慢-它肯定会产生更多IO。