SQL Server - NTEXT 列和字符串操作

Phi*_*lᵀᴹ 11 sql-server sql-server-2008-r2 string

我有一个表,其中有一NTEXT列名为comments. 我有第二个字符串,我们称之为anothercomment(a varchar),它需要放在comments单词 之后的给定字符串中UPDATEHERE

强制转换会nvarchar(max)截断comments字符串,因此我不能使用CHARINDEX()( Msg 8152, Level 16, State 10, Line 2 String or binary data would be truncated.)。我曾经datalength()检查过是否有几千列 > 8000 个字符。

我想要实现的示例(尽管字符串更长):

注释 - This is a test UPDATEHERE This is the end of the test

另一个评论—— . This is inserted.

结果字符串 - This is a test UPDATEHERE. This is inserted. This is the end of the test

我意识到这对于普通的varchar()/ 来说是微不足道的nvarchar(),但是使用它ntext是一个完整而彻底的噩梦。我意识到这是一种已弃用的数据类型,但我没有编写有问题的应用程序。

Pau*_*ite 10

从代码的角度来看,转换为nvarchar(max)和返回ntext确实使生活更简单,但这确实意味着转换和重写整个(可能非常大)值,以及所有 CPU 和日志记录开销。

另一种方法是使用UPDATETEXT. 这已被弃用,就像 一样ntext,但它可以显着减少日志记录开销。不利的一面是,它意味着使用文本指针,并且一次只能对一行进行操作。

以下示例代码使用游标来解决该限制,并使用PATINDEX而不是CHARINDEX因为前者是直接使用的少数函数之一ntext

样本数据

CREATE TABLE dbo.PhilsTable
(
    comment ntext NULL,
    anothercomment nvarchar(50) NULL
);

INSERT dbo.PhilsTable
    (comment, anothercomment)
VALUES 
(
    CONVERT(ntext, 
        N'This is a test UPDATEHERE This is the end of the test ' + 
            REPLICATE (CONVERT(nvarchar(max), N'x'), 1000000)), 
    CONVERT(nvarchar(50), N'. This is inserted.')
),
(
    CONVERT(ntext, 
        N'This is a test UPDATEHERE This is the end of the test ' + 
            REPLICATE (CONVERT(nvarchar(max), N'x'), 1000000)), 
    CONVERT(nvarchar(50), N'. This is inserted.')
),
(
    CONVERT(ntext, 
        N'This is a test UPDATEHERE This is the end of the test ' + 
            REPLICATE (CONVERT(nvarchar(max), N'x'), 1000000)), 
    CONVERT(nvarchar(50), N'. This is inserted.')
);
Run Code Online (Sandbox Code Playgroud)

游标声明

DECLARE c 
    CURSOR GLOBAL 
    FORWARD_ONLY 
    DYNAMIC 
    SCROLL_LOCKS 
    TYPE_WARNING
FOR
SELECT
    TxtPtr = TEXTPTR(PT.comment),
    Src = PT.anothercomment,
    Offset = PATINDEX(N'%UPDATEHERE%', PT.comment) + LEN(N'UPDATEHERE') - 1
FROM dbo.PhilsTable AS PT
WHERE
    PT.comment LIKE N'%UPDATEHERE%'; -- LIKE works with ntext

OPEN c;
Run Code Online (Sandbox Code Playgroud)

处理循环

DECLARE 
    @Ptr binary(16),
    @Src nvarchar(50),
    @Offset integer;

SET STATISTICS XML OFF; -- No cursor fetch plans

BEGIN TRANSACTION;

    WHILE 1 = 1
    BEGIN
        FETCH c INTO @Ptr, @Src, @Offset;

        IF @@FETCH_STATUS = -2 CONTINUE; -- row missing
        IF @@FETCH_STATUS = -1 BREAK; -- no more rows

        IF 1 = TEXTVALID('dbo.PhilsTable.comment', @Ptr)
        BEGIN
            -- Modify ntext value
            UPDATETEXT dbo.PhilsTable.comment @Ptr @Offset 0 @Src;
        END;
    END;

COMMIT TRANSACTION;

CLOSE c; DEALLOCATE c;
Run Code Online (Sandbox Code Playgroud)


Tom*_*m V 8

nvarchar(max)除非您做错了什么,否则转换为应该有效CHARINDEX()

试试这个代码片段,它应该输出你想要的。

-- Create the table
CREATE TABLE [dbo].[PhilsTable](
    [comment] [ntext] NULL,
    [anothercomment] [nvarchar](50) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];

GO

-- insert very long string
INSERT INTO [dbo].[PhilsTable] (comment, anothercomment) VALUES (N'This is a test UPDATEHERE This is the end of the test' + REPLICATE (CAST(N'x' AS nvarchar(max)), 1000000), 'this goes in here');

-- verify data
SELECT DATALENGTH(comment), *  FROM [dbo].[PhilsTable];

-- perform replace
SELECT CAST(REPLACE(CAST(comment AS NVARCHAR(MAX)),'UPDATEHERE','UPDATEHERE' + anothercomment) AS NTEXT) FROM [dbo].[PhilsTable];

DROP TABLE [dbo].[PhilsTable];
Run Code Online (Sandbox Code Playgroud)

感谢Andriy M帮助REPLICATE发表声明。