ntext 列中 REPLACE() 的替代解决方案

Joh*_* N. 7 sql-server regular-expression type-conversion sql-server-2014 sql-server-2016

概述

\n

我有一个图片数据库,其中记录了用相机拍摄的照片的信息。该数据库包含一个有 256 列的表pictures,其中包含有关已拍摄照片的信息。

\n

一列的Comments格式为ntext并包含 CR/LF。
\n还有另外 21 列已配置为ntext.

\n

我使用 SSMS 中的函数将数据库中的数据提取到平面文件中Tasks | Export Data...。然后,导出的数据由外部合作伙伴传输到将在不久的将来使用的新系统。导出文件 (CSV) 包含约 256 列,其中 21 列可能包含 CR/LF。

\n

问题

\n

字段/列包含大量影响数据分析的CommentsCR/LF (SQL: CHAR(13), )。CHAR(10)

\n

我尝试使用REPLACE(expression, value, value)来搜索 CR/LF 并将其替换为 ,@@并且正在考虑Export Data在 SSMS 中使用导出期间实现这一点。

\n

然而,该REPLACE()函数返回一个

\n
\n

消息 8116,级别 16,状态 1,第 4 行
\n参数数据类型 ntext 对于替换函数的参数 1 无效。

\n
\n

...当我执行类似的操作时:

\n
SELECT \'Start *******************\', REPLACE(Comment,\'\n\',\'@@\'), ID, \'********************End\' FROM dbo.pictures\nWHERE Comment LIKE \'%\n%\';\n
Run Code Online (Sandbox Code Playgroud)\n

列注释中的示例数据

\n

发表以下声明:

\n
SELECT Comment FROM dbo.Pictures\nWHERE Comment like \'%\n%\';\n
Run Code Online (Sandbox Code Playgroud)\n

...将检索以下示例Comment记录:

\n
Zwei Fotos von Arenenberg auf einer Seite einer englischen Zeitschrift.\nSeite 148 der Zeitung "The Graphic" vom 4. August 1906 = News from Abroad.\n"The last stage of all": the retreat for aged actors opened last week near Meaux, in France\n1. General view of the home\n2. M. Coquelin reciting in the open-air theater\n\nThe ch\xc3\xa2teau of Arenenberg which has been presented by the Empress Eug\xc3\xa9nie to the canton of Thurgovie\n3. View from the chateau [Arenenberg] over Lake Constance\n4. The ch\xc3\xa2teau of Arenenberg\nThe Empress Eug\xc3\xa9nie has presented to the Swiss Canton of Thurgovie the historical ch\xc3\xa2teau of Arenenberg, where Napoleon III. passed several years of his youth. Queen Hortense, on the fall of the first Empire, fled to Switzerland, and in 1817 purchased the castle, which is delightfully situated on the shore of Lake / Constance. The gift includes a priceless collection of paintings, manuscripts, books, old furniture, and tapestries, among the mos important souvenirs being the camp bed of Napoleon III., and the carriage in which he left Sedan after his defeat. When the alterations are complete the ch\xc3\xa2teau will be opened to the public.\n\n5. The maiden voyage of the new Santos-Dumont flying machine\n6. The room in Viborg where the dissolved Duma met\n                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          .\n
Run Code Online (Sandbox Code Playgroud)\n

是的,有一个空行。句号是我自己插入的,用于显示文本的长度。

\n

常用表达

\n

我导出了数据,然后运行各种正则表达式以省略数据中的 CR/LF。因为该列Comment位于数据中间,所以我必须尝试各种正则表达式字符串:

\n

搜索字符串

\n
([a-zA-Z0-9/,.@():;\\s]+)(\\r\\n)([a-zA-Z0-9/,.@():;"\\s]+)\n([a-zA-Z0-9/,.@():;\\s]+)(\\r\\n\\r\\n)([a-zA-Z0-9/,.@():;"\\s]+)\n([a-zA-Z0-9/,.@():;\\s]+)(\\r\\n\\r\\n\\r\\n)([a-zA-Z0-9/,.@():;"\\s]+)\n([a-zA-Z0-9/,.@():;\\s]+)(\\r\\n\\r\\n\\r\\n\\r\\n)([a-zA-Z0-9/,.@():;"\\s]+)\n([\\w/,.@():;\\s\']+)(\\r\\n)([\\w/,.@():;"\\s]+)\n(;")(\\r\\n)(";)\n(;")(\\r\\n)([\\w/,.@():;\\s\']+)\n(\\w")(\\r\\n)([\\w/,.@():;\\s\']+)\n
Run Code Online (Sandbox Code Playgroud)\n

代替

\n
\\1@@\\3\n
Run Code Online (Sandbox Code Playgroud)\n

该解决方案不是很有效,也不是很高效,因为它需要多次运行和数小时才能整理 CSV 文件。

\n

问题

\n

在导出到 CSV 平面文件期间,如何替换列中的 CR/LF ntext@@有没有比REPLACE我可以使用的选项不同的选项?

\n

限制/观察

\n
    \n
  • 尚未安装集成服务,因此这不是一个选项。
  • \n
  • ntext 字符串可以包含", \'and \xe2\x80\x9c, \xe2\x80\x9d, \xe2\x80\x98\xe2\x80\x99当然还有可选的\xc2\xaband \xc2\xbb
  • \n
  • 我使用该语句分析了该ntext列中的数据,收到的反馈是一条记录包含5'562个字符。CommentSELECT MAX(DATALENGTH(Comment)) FROM Pictures;
  • \n
\n

我创建了一个db<>fiddle,其中包含表的基本定义和示例数据以及失败的REPLACE()语句。

\n

Dav*_*ett 8

SQL Server 的字符串处理函数在处理长字符串时有点不一致,但如果您注意确保要搜索的输入是,NVARCHAR(MAX)那么该REPLACE()函数将处理长度超过 8,000 字节(“N”类型为 4,000 个字符)的数据。这意味着您可以NTEXT通过将长值转换为 NVARCHAR(MAX) 并再次转换回来来操作长值,而不会被截断,如下所示:

\n
INSERT @t(tt) \n    SELECT CAST(\n              REPLICATE(CAST(N'x' AS NVARCHAR(MAX)), 16000) -- Note: for replicate to work as expected make sure its input is explicitly a long type\n            + N'\xe2\x98\xa0'\n        AS NTEXT)\nSELECT DATALENGTH(tt) FROM @t -- 32,002 data length so we have more than the limit of non-MAX character types\n-- Now test working with the long value:\nSELECT DATALENGTH(CAST(REPLACE(CAST(tt AS NVARCHAR(MAX)),'x','y') AS NTEXT)) FROM @t \n-- still 32,002, has not been truncated\nSELECT DATALENGTH(CAST(REPLACE(CAST(tt AS NVARCHAR(MAX)),'x','yz') AS NTEXT)) FROM @t \n-- 64,002\nSELECT RIGHT(CAST(CAST(REPLACE(CAST(tt AS NVARCHAR(MAX)),'x','yz') AS NTEXT) AS NVARCHAR(MAX)), 10) FROM @t \n-- paranoia check, we've not lost the non-ASCII character at the end through truncation or conversion\n
Run Code Online (Sandbox Code Playgroud)\n

但这不会特别有效,特别是如果这些NTEXT列中有很长的值。

\n
\n

因此,对于您的 db-fiddle 示例:

\n
select REPLACE(CAST(Comment AS NVARCHAR(MAX)), CHAR(10), '@@') from Pictures;\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,小提琴已将双字节 EOL 替换为CHAR(10). 此外,如果接收应用程序期望这样做,您可能需要转换回NTEXT(如我之前的示例中所做的那样),例如,如果 SSIS 在期望遗留 blob 类型时收到正常的长字符串值,那么它肯定会抱怨。

\n