我有一个sql server db,它有一个表,它在nvarchar列中存储纯文本值。不幸的是,C#代码中的一个错误是在将汉字插入表中之前对中文字符运行Encoder.HtmlEncode()。例如,您好的文本值作为您好
有没有办法只使用T-sql清理这些数据?这个数据库被严重锁定,所以除了T-sql之外我不能轻易地运行任何代码。
答案 0 :(得分:0)
从问题看来,你有一个选择。
您可以创建一个临时表来存储字符的HTML实体。作为一个例子;
CREATE TABLE dbo.TempHost
{
Entity varchar(255),
Character nvarchar(255)
}
然后,您实际上可以将数据作为csv online(http://www.khngai.com/chinese/charmap/tbluni.php?page=0或复制并粘贴到Excel)查找,并将其导入表中。从那以后,您需要做的就是扫描数据并调用REPLACE()函数并进行更新。
答案 1 :(得分:0)
这是一个有趣的挑战,有趣的是,我的意思并不是很有趣。 T-SQL在字符串操作方面非常糟糕。为了使它更好,HTML实体实际上编码Unicode代码点,并且没有简单的方法将其转换为T-SQL中的Unicode字符。
使用查找表可能是最可行的方法,因为它可能比我在此提出的更有效:使用函数来替换实体。警告:标量值函数在T-SQL中执行可怕,字符串操作也不会太快。尽管如此,我还是以鼓舞人心的目的来表达这一点:
CREATE FUNCTION dbo._ConvertEntities(@in NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS BEGIN
WHILE 1 = 1 BEGIN;
DECLARE @entityStart INT = CHARINDEX('&#x', @in);
IF @entityStart = 0 BREAK;
DECLARE @entityEnd INT = CHARINDEX(';', @in, @entityStart)
DECLARE @entity VARCHAR(MAX) = SUBSTRING(@in, @entityStart + LEN('&#x'), @entityEnd - @entityStart - LEN('&#x'));
IF @entity NOT LIKE '[0-9A-F][0-9A-F][0-9A-F][0-9A-F]' RETURN @in;
DECLARE @entityChar NCHAR(1) = CONVERT(NCHAR(1), CONVERT(BINARY(2), REVERSE(CONVERT(BINARY(2), @entity, 2))));
SET @in = STUFF(@in, @entityStart, @entityEnd - @entityStart + 1, @entityChar);
END;
RETURN @in;
END;
除了性能问题之外,此函数还有一个主要缺点,即它仅适用于&#x????;
形式的实体,其中????
为四个十六进制数字。它对其他实体(如需要代理的那些实体,编码为十进制的实体或像"
这样的特殊实体)非常糟糕。在这种情况下,我已经挽救了它。尽管将其扩展为处理单字节实体相当容易,但将其扩展到> 4会很痛苦。
实际上,您希望使用真正的编程语言在客户端软件中执行此操作。即使数据库已被充分锁定而您无法直接执行查询,但如果数据不是太多,您可能会查询数据,并且可以使用生成的语句(如果需要,可以使用很多语句)插入数据。非常慢,但或多或少可行。
为了完整起见,我还提到了使用CLR integration在SQL Server中运行CLR代码的选项。这要求服务器已经允许这样或者你可以重新配置它以允许它(如果它被“严重锁定”,则不太可能)。这将是有吸引力的主要原因是因为它在CLR代码中解码实体肯定更容易和更快,并且使用CLR集成意味着您不使用客户端代码(因此数据不会离开服务器)。另一方面,由于您需要对计算机进行管理访问以部署程序集,因此这似乎是理论上的优势。然而,就性能而言,它可能无法被击败。
答案 2 :(得分:0)
你可以利用所有字符存储的事实,一切都以"&#x"开头。并且长八个字符。您可以使用类似下面的示例来循环查看表格,更新剪掉不良字符。
DECLARE @str VARCHAR(100)
SET @str = 'Hello 頶頴World'
DECLARE @pos int SELECT @pos = CHARINDEX('&#x', @str)
WHILE @pos > 0
BEGIN
SET @str = LEFT(@str, @pos -1) + RIGHT(@str, LEN(@str) -@pos - 8)
SELECT @pos = CHARINDEX('&#x', @str)
END
SELECT @str
答案 3 :(得分:0)
HTML编码与XML编码不同,但感谢this question,我意识到实现这一目标有一种非常简单的方法:
SELECT
REPLACE(
CONVERT(NVARCHAR(MAX),
CONVERT(XML,
REPLACE(REPLACE(_column_, '<', '<'), '"', '"')
)
),
'<', '<'
)
坚持UPDATE
,你已经完成了。好吧,差不多 - 如果代码包含非é
等非XML转义实体,则需要单独替换这些实体。此外,我们确实需要围绕XML转义的问题跳舞(因此<
替换,以防某处有<
。
它可能仍然需要一些改进,但这确实看起来比标量值函数更有希望。 : - )