SQL Server Combine multiple text injection

mmvthczy  于 2023-10-15  发布在  其他
关注(0)|答案(2)|浏览(76)

I have a table that has these records on SQL Server

RepID   iBegin    iEnd    RepText
1       10        17      This is a profile of ... Moreover Toyota has been ... such as Mazda also ... 
1       38        44      This is a profile of ... Moreover Toyota has been ... such as Mazda also ... 
1       77        82      This is a profile of ... Moreover Toyota has been ... such as Mazda also ... 
2       21        24      ... flights to USA will be...weather temp is 73 degrees ...
2       82        82      ... flights to USA will be...weather temp is 73 degrees ...

this table has a text (HTML) and I need to highlight the text that is in between iBegin and iEnd by adding the <red> before and after the highlighted text

I did that on the row level

SELECT RepID, RepText, SUBSTRING(RepText,0, iBegin) + '<red>' + SUBSTRING(RepText,iBegin, iEnd-iBegin + 1) + '<\red>' + SUBSTRING(RepText, iEnd, Len(RepText)-iEnd + 1)
FROM table

but could not do that with group by so all highlights show in a single record like this

RepID    RepText
1          This is a <red>profile</red> of ... Moreover <red>Toyota</red> has been ... such as <red>Mazda</red> also ... 
2          ... flights to <red>USA</red> will be...weather temp is <red>73</red> degrees ...

Any idea how to do that?

yjghlzjz

yjghlzjz1#

Depending on your version of SQL Server and whether such string processing is best done in the database...

with data as (
    select RepID, iBegin + 1 as iBegin, iEnd + 1 as iEnd, RepText, /* adjust to 1-based index */
        1 + lag(iEnd, 1, 0) over (partition by RepID order by iBegin) as prevBegin,
        1 + max(iEnd) over (partition by RepID) as lastBegin 
    from T
)
select RepID,
    string_agg(
        concat(
            substring(RepText, prevBegin, iBegin - prevBegin),
            '<red>',
            substring(RepText, iBegin, iEnd - iBegin),
            '</red>'
        ), ''
    ) within group (order by iBegin)
    + substring(min(RepText), min(lastBegin), 1000)
from data
group by RepID;

This handles each wrapped segment with the non-wrapped segment just before it (via lag() ) in pairs. Each of those must then be concatenated in proper order along with the final segment at the end. This does assume no overlap in your offsets but that's pretty much a given anyway.

https://dbfiddle.uk/n2beW4E0

f5emj3cl

f5emj3cl2#

I'm not sure if your iBegin and iEnd are correct... Here's a way to do it with a UDF and GROUP BY :

First the UDF

CREATE OR ALTER FUNCTION dbo.Repl(@text nvarchar(max), @words nvarchar(max))
RETURNS nvarchar(max) 
AS
 BEGIN
    DECLARE @pre nvarchar(max) = '';
    SET @words = @words + ';';

    WHILE LEN(@words) > 0
        BEGIN
            SET @pre = LEFT(@words, CHARINDEX(';', @words) - 1);
            SET @text = REPLACE(@text, @pre, ' <red>' + SUBSTRING(@pre, 2, LEN(@pre) - 1) + '<\red> ');
            SET @words = REPLACE(@words, @pre + ';', '');
        END
    RETURN @text
 END;

Then the call would be

WITH pre AS
(
    SELECT 
            RepID,
            RepText,
            STRING_AGG(' ' + SUBSTRING(RepText, iBegin + 1, iEnd - iBegin) + ' ', ';') AS Words
    FROM [table]
    GROUP BY RepID, RepText
)

SELECT
        RepID,
        dbo.Repl(RepText, Words) AS RepText
FROM pre;

And if your data looks like this, you would get your expected output:

CREATE TABLE [table]
(
    RepID int,
    iBegin int,
    iEnd int,
    RepText nvarchar(max)
);

INSERT INTO [table]
VALUES
    (1, 10, 17, 'This is a profile of ... Moreover Toyota has been ... such as Mazda also ...'),
    (1, 34, 40, 'This is a profile of ... Moreover Toyota has been ... such as Mazda also ...'),
    (1, 62, 67, 'This is a profile of ... Moreover Toyota has been ... such as Mazda also ...'),
    (2, 15, 18, '... flights to USA will be...weather temp is 73 degrees ...'),
    (2, 45, 47, '... flights to USA will be...weather temp is 73 degrees ...');

相关问题