SQL Server - คอลัมน์ NTEXT และการจัดการสตริง


11

ฉันมีตารางที่มีNTEXTคอลัมน์ชื่อcommentsหนึ่ง ฉันมีสตริงที่สองขอเรียกว่าanothercomment(กvarchar) ที่ความต้องการวางภายในที่กำหนดสตริงหลังคำว่าcommentsUPDATEHERE

กำลังส่งเพื่อ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เป็นฝันร้ายที่สมบูรณ์และสมบูรณ์ที่สุดที่จะทำงานด้วย ฉันรู้ว่ามันเป็นประเภทข้อมูลที่เลิกใช้แล้ว แต่ฉันไม่ได้เขียนแอปพลิเคชันที่เป็นปัญหา

คำตอบ:


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;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.