63

###RFC 4180:

RFC 4180定义Common Format and MIME Type for Comma-Separated Values (CSV) Files. 的要求之一RFC 4180如下所述。这是#7RFC 链接中的要点。

If double-quotes are used to enclose fields, then a double-quote
appearing inside a field must be escaped by preceding it with
another double quote.  For example:

"aaa","b""bb","ccc"

###SQL Server 2000:

DTS Export/Import WizardinSQL Server 2000似乎符合上述标准,尽管 RFC 4180 本身似乎仅在2005 年10 月发布。我正在使用下面所述的SQL Server 2000版本。

Microsoft SQL Server  2000 - 8.00.2039 (Intel X86) 
May  3 2005 23:18:38 
Copyright (c) 1988-2003 Microsoft Corporation
Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4)

###SQL Server 2012:

SQL Server Import and Export WizardinSQL Server 2012不会根据 RFC 4180 中定义的标准将数据从表导出到 CSV 文件。我使用的是下面所述的SQL Server 2012版本。

Microsoft SQL Server 2012 - 11.0.2316.0 (X64) 
Apr  6 2012 03:20:55 
Copyright (c) Microsoft Corporation
Enterprise Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)

###问题模拟:

这是我在SQL Server 2000SQL Server 2012中运行的示例。我运行以下查询来创建一个表并插入几条记录。该ItemDesc列包含带有双引号的数据。我的目的是使用它们内置的导出数据向导从这两个 SQL Server 版本中导出数据,并比较生成的 CSV 文件。

CREATE TABLE dbo.ItemInformation(
    ItemId nvarchar(20) NOT NULL,
    ItemDesc nvarchar(100) NOT NULL
) 
GO

INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100338754', 'Crown Bolt 3/8"-16 x 1" Stainless-Steel Hex Bolt');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('202255836', 'Simpson Strong-Tie 5/8" SSTB Anchot Bolt');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100171631', 'Grip-Rite #11 x 1-1/2" Electro-Galvanized Steel Roofing Nails');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('202210289', 'Crown Bolt 1/2" x 3" "Zinc-Plated" Universal Clevis Pin');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('100136988', 'Tapcon 3/16" x 1-3/4" Climaseal Steel "Flat-Head" Phillips Concrete Anchors (75-Pack)');
INSERT INTO dbo.ItemInformation (ItemId, ItemDesc) VALUES ('203722101', 'KwikTap 3/16" x 2-1/4" "Flat-Head" Concrete Screws (100-Pack)');
GO

DTS Export/Import WizardSQL Server 2000,我使用以下设置将数据导出到 CSV 文件。我将文件保存在 name 下SQLServer2000_ItemInformation.csv

DTS 导出/导入向导

SQL Server Import and Export WizardSQL Server 2012,我使用以下设置将数据导出到 CSV 文件。我将文件保存在 name 下SQLServer2012_ItemInformation.csv

SQL Server 导入和导出向导 - 选择目标

SQL Server 导入和导出向导 - 配置平面文件目标

这是使用 Beyond Compare 对两个文件进行的比较。左边是生成的文件SQL Server 2000,右边是生成的文件SQL Server 2012。您会注意到左侧文件中SQL Server 2000包含额外的双引号,以补偿数据列中嵌入的引号。这符合中指定的标准,RFC 4180但它显然从生成的文件中丢失SQL Server 2012

文件比较

###网络搜索:

我在网上搜索了这个错误并找到了以下链接。以下是 Microsoft Connect 上的错误报告。所有这些问题似乎都与导入文件有关,但与导出数据无关。所有这些错误都已作为Fixed.

以下 MSDN 博客上的帖子指出,SQL Server 2012 中已对以下方面进行了更改Flat file source supports embedded qualifiers and a variable number of columns per row

MSDN 博客上的另一篇文章在该部分下也有相同的说明Embedded Qualifiers

###我知道的解决方法:

我知道通过编写一个查询来解决此问题,该查询将"用两个双引号 ( ) 替换列数据中的所有双引号 ( ""),以便导出的文件最终得到正确的嵌入限定符数据。这将避免直接从表中提取数据。

###我的问题:

  • 我不知道这个问题是否真的在SQL Server 2012. importing是否仅针对具有嵌入文本限定符的文件和notCSVexporting数据修复了此问题?

  • 可能,我显然做错了什么并且错过了显而易见的事情。有人可以向我解释我在这里做错了什么吗?

###微软连接:

我已在 Microsoft Connect 网站上提交了一份错误报告以获取他们的反馈。这是错误报告的链接。如果您同意这是一个错误,请访问以下链接在Microsoft Connect网站上投票。

导出到 CSV 期间的嵌入文本限定符不符合 RFC 4180

4

3 回答 3

8

我不会提供这个答案,除非你非常努力地记录它并且一个月后没有答案。所以,就这样吧。您唯一的选择似乎是更改数据或更改工具。

可能,我显然做错了什么并且错过了显而易见的事情。有人可以向我解释我在这里做错了什么吗?

当工具坏了而供应商不在乎时,继续尝试是错误的。是时候切换了。您投入了大量精力来研究它是如何被破坏的,并证明它不仅违反了 RFC,而且违反了该工具自己的先前版本。你还需要多少证据?

CSV 也是船锚。如果可以选择,最好使用普通的分隔文件格式。对于很多应用程序,制表符分隔是好的。最好的分隔符 IMO 是“\”,因为该字符在英文文本中没有位置。(另一方面,它不适用于包含 Windows 路径名的数据。)

CSV 作为交换格式有两个问题。首先,它不是那么标准。无论 RFC 怎么说,不同的应用程序识别不同的版本。第二个(和相关的)是它不构成 CS 术语中的正则语言,这就是为什么它不能被解析为正则表达式的原因。与^([^\t]*\t)*[\t]*$制表符分隔的行进行比较。CSV 定义的复杂性的实际含义是(见上文)处理它们的工具相对缺乏以及它们不兼容的趋势,尤其是在凌晨。

如果您让 CSV 和 DTS 启动,您有很好的选择,其中之一是bcp.exe. 它非常快速且安全,因为微软多年来一直没有尝试对其进行更新。我对 DTS 了解不多,但如果您必须将其用于自动化,IIRC 有一种方法可以调用外部实用程序。但请注意,这bcp.exe不会可靠地将错误状态返回给 shell。

如果您决定使用 DTS 并坚持使用 CSV,那么剩下的最佳选择就是编写一个视图,为它准备适当的数据。如果回到那个角落,我会创建一个名为“DTS2012CSV”的模式,这样我就可以编写select * from DTS2012CSV.tablename,让任何关心它的人都有机会理解它(因为你会记录它,不是吗?视图文本中的注释?)。如果需要,其他人可以将其技术复制到其他损坏的提取物中。

HTH。

于 2013-03-14T00:42:35.013 回答
2

我知道这已经有两年了,但我现在也遇到了这个问题,因为我们需要使用 SQL Server 2008 来签订我们的合同(不要问)。读完这个问题后,我意识到我需要做替换建议,但是当我在查询中去做时,我遇到了截断问题,因为在查询本身中使用 replace() 函数会将文本转换为默认为 varchar(8000)。

但是,我发现我可以在 DB Source 和 Flat File 对象之间使用 Derived Column 步骤来做同样的事情。例如,我有一个名为“short_description”的列,其中可能包含引号,所以我只是使用以下函数作为表达式,并在派生列中选择了“替换 short_description”:

REPLACE(short_description,"\"","\"\"")

这似乎为我解决了这个问题。

于 2015-08-05T14:37:42.800 回答
0

名字和姓氏通常在同一个字段中并采用格式(姓氏,名字)。如果您在数据库中使用 Tasks->Export Data(而不是通过 SSIS,您有更多选项)并且您需要以逗号分隔文件的形式导出到 CSV,则这需要是文本限定的。

这将有助于您需要双引号的非空选定字段...

CASE WHEN NOT PersonName IS NULL AND LEN(PersonName) > 0 THEN QUOTENAME(PersonName, '"') ELSE NULL END as 'PersonName'

结果:

人名

“柯林斯,扎克瑞 E”

于 2018-06-06T20:55:18.987 回答