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)
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
发表声明。
归档时间: |
|
查看次数: |
7550 次 |
最近记录: |