我有一个遗留系统,表中有大约1000万行。在该表中有一个类型为text
的列,其中大多数是标准文本,但其中大约有50万行有RTF标记。我需要将RTF格式的文本转换为纯文本。
我的当前方法是,我有一个C#程序,它使用SqlDataAdapter
将查询加载到DataTable中,并使用winforms RichTextBox
控件进行转换。
void bw_DoWork(object sender, DoWorkEventArgs e)
{
count = 0;
rtbRTFToPlain = new RichTextBox();
using (SqlDataAdapter ada = new SqlDataAdapter("select note_guid, notes from client_notes", Globals.SQLConnectionString))
using(SqlCommandBuilder cmb = new SqlCommandBuilder(ada))
{
DataTable dt = new DataTable();
ada.UpdateCommand = cmb.GetUpdateCommand();
ada.Fill(dt);
int reportEvery = dt.Rows.Count / 100;
if (reportEvery == 0)
reportEvery = 1;
foreach (DataRow row in dt.Rows)
{
if (count % reportEvery == 0)
bw.ReportProgress(count / reportEvery);
try
{
if (((string)row["notes"]).TrimStart().StartsWith("{") == true)
{
rtbRTFToPlain.Rtf = (string)row["notes"];
row["notes"] = rtbRTFToPlain.Text;
}
}
catch
{
}
count++;
}
bw.ReportProgress(100);
this.Invoke(new Action(() =>
{
this.ControlBox = false;
this.Text = "Updating database please wait";
}));
ada.Update(dt);
}
}
这对于小型表非常有用,但是这是我第一次在一个拥有如此大的数据集的表上运行它(有些rtf文件可以有几兆字节大小的嵌入图片),而且我的C#程序正在获取C#错误。
我知道我可以把我的查询分成一个更小的批次,但是我想知道是否有更好的方法来去除RTF格式。
我应该只做与当前解决方案相同的事情,而只是一次查询较小的数据块,还是有更好的方法来做到这一点?
发布于 2012-05-04 20:21:16
最后,我创建了一个CLR函数来转换它。
我找到了这个图书馆,然后对它做了一些调整,删除了一些我不需要的东西,比如日志记录和绘图方法,这样我就可以把它标记为安全了。
然后我就上了这个小班。
using System.Data.SqlTypes;
using Itenso.Rtf.Converter.Text;
using Itenso.Rtf.Support;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString RtfToPlainText(SqlString text)
{
if (text.Value.StartsWith(@"{\rtf"))
{
RtfTextConverter textConverter = new RtfTextConverter();
RtfInterpreterTool.Interpret(text.Value, textConverter);
return textConverter.PlainText;
}
else
return text;
}
}
并在SQL中运行此程序。
sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO
CREATE ASSEMBLY ConversionsSqlExtensionsAssembly
from 'E:\Code\ConversionsSqlExtensions\bin\Debug\ConversionsSqlExtensions.dll'
WITH PERMISSION_SET = safe
go
CREATE function RtfToPlainText(@value nvarchar(max))
returns nvarchar(max)
AS EXTERNAL NAME ConversionsSqlExtensionsAssembly.StoredProcedures.RtfToPlainText
而且速度快,效果很好!
发布于 2014-05-30 18:47:26
我和使用Itenso做了同样的事情,但在我的例子中,在我的SQL2008R2数据库中将其标记为安全之前,还有很多工作要做。
首先,像Scott一样,我不得不删除对System.Drawing的引用。我发现最简单的方法是删除引用,重新编译,然后重写使用库的代码。在大多数情况下,我只是从使用它的VOID函数中删除了所有代码,并且在我无法将绘图/Color对象更改为"object“对象的情况下。
我必须做的另一件事是删除对log4net的任何和所有引用,因为它引用的库System.DirectoryServices也不能被标记为安全。这有点困难,但总的来说,我也采取了同样的方法。
最后,在我这样做之后,我收到了关于设置静态值的抱怨,这在安全的CLR函数中是不允许的。因此,我更新了代码,将所有静态值更改为READONLY,这起了作用(这几乎是在代码的“日志”部分,而我并不真正关心这个部分)。
我的最终CLR代码如下所示:
[Microsoft.SqlServer.Server.SqlFunction]
[return: SqlFacet(MaxSize=-1)]
public static SqlChars RTFFix([SqlFacet(MaxSize=-1)]string rtfField)
{
SqlChars returnChars;
try
{
RtfTextConverter textConverter = new RtfTextConverter();
RtfInterpreterTool.Interpret(rtfField, textConverter);
returnChars = new SqlChars(new SqlString(textConverter.PlainText.Trim()));
}
catch (Exception e)
{
returnChars = new SqlChars(new SqlString(rtfField));
}
return returnChars;
}
发布于 2012-05-04 15:43:41
我编写了一个小的SQL函数,将文本从带标记的字符串中删除:http://cookingwithsql.com/index.php?option=com_content&task=view&id=65&Itemid=60。
不幸的是,它只处理多达8000个字符的字符串数据。如果您正在SQL 2005和更高版本上运行,也许可以将其更改为使用varchar(max)。
用法:
select dbo.ScrapeText('<I love SQL> gobbldygook font 12 blah blah') as 'Result'
Result
----------------------------
I love SQL
我会在这里张贴消息来源,以供快速参考。
use master
IF (object_id('dbo.ScrapeText') IS NOT NULL)
BEGIN
PRINT 'Dropping: dbo.ScrapeText'
DROP function dbo.ScrapeText
END
GO
PRINT 'Creating: dbo.ScrapeText'
GO
CREATE FUNCTION dbo.ScrapeText
(
@string varchar(8000)
)
returns varchar(8000)
AS
BEGIN
---------------------------------------------------------------------------------------------------
-- Title: ScrapeText
--
-- Date Created: April 4, 2006
--
-- Author: William McEvoy
--
-- Description: This function will attempt to remove markup language formatting from a string. This is
-- accomplished by concetenating all text contained between greater than and less
-- than signs within the formatted text.
--
---------------------------------------------------------------------------------------------------
-- Date Revised:
-- Author:
-- Reason:
---------------------------------------------------------------------------------------------------
declare @text varchar(8000),
@PenDown char(1),
@char char(1),
@len int,
@count int
select @count = 0,
@len = 0,
@text = ''
---------------------------------------------------------------------------------------------------
-- M A I N P R O C E S S I N G
---------------------------------------------------------------------------------------------------
-- Add tokens
select @string = '>' + @string + '<'
-- Replace Special Characters
select @string = replace(@string,' ',' ')
-- Parse out the formatting codes
select @len = len(@string)
while (@count <= @len)
begin
select @char = substring(@string,@count,1)
if (@char = '>')
select @PenDown = 'Y'
else
if (@char = '<')
select @PenDown = 'N'
else
if (@PenDown = 'Y')
select @text = @text + @char
select @count = @count + 1
end
RETURN @text
END
GO
IF (object_id('dbo.ScrapeText') IS NOT NULL)
PRINT 'Function created.'
ELSE
PRINT 'Function NOT created.'
GO
https://dba.stackexchange.com/questions/17454
复制相似问题