NTEXT
という名前のcomments
列を持つテーブルがあります。 2番目の文字列があります。それを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
は完全に動作する完全な悪夢です。私はそれが非推奨のデータ型であることを理解していますが、問題のアプリケーションを記述していません。
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];
REPLICATE
ステートメントを手伝ってくれて Andriy M に感謝します。
nvarchar(max)
に変換し、ntext
に戻すと、コードの観点からは簡単になりますが、すべての(おそらく非常に大きい)値を変換および書き換えることを意味し、すべてのCPUとロギングオーバーヘッドが意味します。
UPDATETEXT
を使用することもできます。これは、ntext
と同様に非推奨ですが、ログのオーバーヘッドを大幅に削減できます。欠点は、テキストポインターを使用することを意味し、一度に1行のみを操作します。
次のコード例では、カーソルを使用してその制限を回避し、PATINDEX
の代わりにCHARINDEX
を使用しています。前者は いくつかの関数 の1つであるため、 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;