SQL Server-NTEXT列和字符串处理


11

我有一张桌子,有一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是一个完全而彻底的噩梦。我意识到这是不赞成使用的数据类型,但是我没有编写有问题的应用程序。

Answers:


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];

感谢Andriy M协助您完成REPLICATE声明。


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.')
);

游标声明

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;

处理循环

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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.