在准备好的语句中使用游标进行更新

Posted

技术标签:

【中文标题】在准备好的语句中使用游标进行更新【英文标题】:Using cursor for update inside a prepared statement 【发布时间】:2018-08-05 23:08:44 【问题描述】:

我在 JDBC 准备语句中使用了以下游标,如下所示:

DECLARE c CURSOR GLOBAL FORWARD_ONLY DYNAMIC SCROLL_LOCKS TYPE_WARNING 
FOR 
SELECT TxtPtr = TEXTPTR(PT.BODY), Src = N'ReplaceString', 
Offset = PATINDEX(N'%[^A-Za-z0-9]SearchThis[^A-Za-z0-9]%', PT.BODY) 
FROM       dbo.BODYCONTENT AS PT    
WHERE       PT.BODY LIKE N'%[^A-Za-z0-9]SearchThis[^A-Za-z0-9]%';
OPEN c;
DECLARE @Ptr binary(16), @Src nvarchar(50), @Offset integer;
FETCH NEXT FROM c INTO @Ptr, @Src, @Offset;
WHILE @@FETCH_STATUS=0
BEGIN;
BEGIN TRANSACTION;
UPDATE dbo.BODYCONTENT SET BODY = ltrim(rtrim(replace
(replace(replace(N' ' + cast(BODY as nvarchar(max)) + N' ','    
','<>'),'>' + @Offset + '<','>' + @Src+ '<'),'<>',' '))) 
from dbo.BODYCONTENT
COMMIT TRANSACTION;
FETCH NEXT FROM c INTO @Ptr, @Src, @Offset;
END;CLOSE c; DEALLOCATE c;

当我直接在数据库中执行上述游标时,它只有在将@Src@Offset 的值明确指定为'&gt;SearchThis&lt;','&gt;ReplaceString&lt;' 时才有效

如何在查询中使用@Src@Offset

JDBC 准备好的语句:

String sql3 = "DECLARE c CURSOR GLOBAL FORWARD_ONLY DYNAMIC 
                SCROLL_LOCKS TYPE_WARNING FOR" +    
              " SELECT TxtPtr = TEXTPTR(PT.BODY), Src = N'+ ? + ', 
               Offset = PATINDEX(N'%[^A-Za-z0-9] + ? + [^A-Za-z0-9]%', PT.BODY)" +
               " FROM dbo.BODYCONTENT AS PT" + 
               " WHERE PT.BODY LIKE N'%[^A-Za-z0-9]?[^A-Za-z0-9]%';" + 
               " OPEN c;" + 
               " DECLARE @Ptr binary(16), @Src nvarchar(50), @Offset    
                  integer;" + 
               " FETCH NEXT FROM c INTO @Ptr, @Src, @Offset;" + 
               " WHILE @@FETCH_STATUS=0" + 
               " BEGIN" + 
               " BEGIN TRANSACTION;" + 
               " UPDATE dbo.BODYCONTENT SET BODY = ltrim(rtrim(replace(replace(replace(N' ' + cast(BODY as nvarchar(max)) + N' ',' ','<>'),'>' + @Offset +'<','>' + @Src + '<'),'<>',' '))) from dbo.BODYCONTENT" + 
        "COMMIT TRANSACTION;" + 
        "FETCH NEXT FROM c INTO @Ptr, @Src, @Offset;" + 
        "END;CLOSE c; DEALLOCATE c;";



pstmt = conn.prepareStatement(sql3);



            pstmt.setNString(1, searchStr);
            pstmt.setNString(2, replaceString);
            pstmt.setNString(3, searchStr);


            pstmt.executeUpdate();

我应该如何实现这个?

我认为问题在于我将? 提供给setNString 设置的参数。游标本身没有问题,游标适用于硬编码值。但我希望能够使用 setNString 或类似的东西从配置文件中传入 java 应用程序中的参数。

【问题讨论】:

首先,你应该摆脱你的光标。更新有点令人困惑,因为您对每一行都进行了更新,而不仅仅是游标中的那一行。但是,当您在 sql 数据库中工作时,您需要考虑基于集合,而不是基于程序。将查询重构为一个简单的update table set blah where blah 【参考方案1】:

不试图理解你所有的 patindex 并替换字符串(因为我的大脑爆炸了),它应该是一个简单的无光标更新语句,如下所示:

UPDATE dbo.BODYCONTENT SET BODY = ltrim(rtrim(replace
(replace(replace(N' ' + cast(BODY as nvarchar(max)) + N' ','    
','<>'),'>' + PATINDEX(N'%[^A-Za-z0-9]SearchThis[^A-Za-z0-9]%', PT.BODY)  + '<','>' + N'ReplaceString'+ '<'),'<>',' '))) 
from dbo.BODYCONTENT
WHERE PT.BODY LIKE N'%[^A-Za-z0-9]SearchThis[^A-Za-z0-9]%';

【讨论】:

您好 TomC,感谢您的回复。但问题是我正在尝试使用参数化查询。当我对字符串“SearchThis”和“ReplaceString”进行硬编码时,我的光标工作得很好。但问题是当我尝试使用 setNString 或 setString 时,它不起作用。

以上是关于在准备好的语句中使用游标进行更新的主要内容,如果未能解决你的问题,请参考以下文章

更新数据库中的数据 - 准备好的语句(PHP)

无法在准备好的 INSERT 语句中的 python mysql.connector 中使用 None (NULL) 值

准备好的语句更新 - 性能改进

如何在 Java 中使用准备好的语句进行选择查询?

MySQL & PHP 更新问题,使用准备好的语句

使用准备好的语句时出现 Camel -Spring SQLException