将数据导出到CSV平面文件时如何解决embedded的文本限定符问题?
RFC 4180:
RFC 4180 Common Format and MIME Type for Comma-Separated Values (CSV) Files
定义了Common Format and MIME Type for Comma-Separated Values (CSV) Files
。 RFC 4180
的要求之一如下所述。 这是RFC链接中的#7
点。
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:
在SQL Server 2000
DTS Export/Import Wizard
似乎符合上述标准,即使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 Wizard
SQL Server 2012
中的“ SQL Server Import and Export Wizard
不会根据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 2000和SQL Server 2012中运行的示例。 我运行下面的查询来创build一个表并插入几条logging。 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
在SQL Server 2000
的DTS Export/Import Wizard
中,我使用以下设置将数据导出到CSV文件。 我用名字SQLServer2000_ItemInformation.csv
保存了这个文件。
在SQL Server Import and Export Wizard
2012中的SQL Server Import and Export Wizard
中,我使用以下设置将数据导出到CSV文件。 我以名称SQLServer2012_ItemInformation.csv
保存了该文件。
这里是比较使用Beyond Compare的两个文件。 左侧包含由SQL Server 2000
生成的文件,右侧包含由SQL Server 2012
生成的文件。 您可以注意到来自SQL Server 2000
的左侧文件包含额外的双引号以补偿数据列中的embedded式引号。 这符合在RFC 4180
指定的标准,但是它显然在SQL Server 2012
生成的文件中不存在
在网上search:
我在网上search了这个bug,发现了以下链接。 以下是Microsoft Connect上的错误报告。 所有这些问题似乎都与导入文件有关,但与导出数据无关。 所有这些错误已被closures为Fixed
。
- SSIS平面文件分析器不会读取embedded在文本数据中的列分隔符
- 平面文件连接pipe理器不处理CSV文件中的文本分隔符
- 平面文件导入中的embedded式引号失败
- BUG:平面文件连接pipe理器:多字符文本限定符不会加载所有数据
MSDN博客下面的post指出,在SQL Server 2012中,对Flat file source supports embedded qualifiers and a variable number of columns per row
进行了更改
- SSIS – SQL Server Denali中的新function
MSDN博客上的另一篇文章在Embedded Qualifiers
一节中指出了相同的内容。
- Denali中的平面文件源更改
我知道的解决方法是:
我知道一个解决方法,通过编写一个查询来解决这个问题,该查询将用两个双引号( ""
)replace列数据中的所有双引号( "
),这样导出的文件将以正确的embedded限定符数据结束。将避免直接从表中提取数据。
我的问题:
-
我不知道这个问题是否已经在
SQL Server 2012
真正解决了。 此问题是否仅在importing
embedded了文本限定符的文件时才被解决,而not
用于exporting
数据exporting
为CSV? -
也许,我显然做错了事情,错过了显而易见的事实。 有人能向我解释我在这里做错了吗?
Microsoft Connect:
我已经在Microsoft Connect网站上提交了一个错误报告以获得他们的反馈。 这里是错误报告的链接。 如果您同意这是一个错误,请访问以下链接,在Microsoft Connect
网站上投票。
导出为CSV时embedded的文本限定符不符合RFC 4180
我不会提供这个答案,只是你很努力地logging下来,一个月后就没有答案了。 所以,在这里。 您唯一的select似乎是更改数据或更改工具。
也许,我显然做错了事情,错过了显而易见的事实。 有人能向我解释我在这里做错了吗?
当工具被打破,供应商不在意,继续尝试是错误的。 是时候切换了。 你花费了大量的精力研究它是如何被破坏的,并且certificate它不仅违反了RFC而且还违反了该工具自己的先前版本。 你需要多less证据?
CSV也是船锚。 如果您有select,最好使用普通的分隔文件格式。 对于大量的应用程序,制表符分隔很好。 最好的分隔符IMO是'\',因为那个字符在英文文本中没有地位。 (另一方面,它不适用于包含Windowspath名的数据。)
CSV作为交换格式有两个问题。 首先,这不是那个标准。 不pipeRFC可以说,不同的应用程序都会识别不同的版本。 其次(和相关的)是,它不构成一个正规的语言在CS条款,这就是为什么它不能被parsing为一个正则expression式。 与制表符分隔的行比较^([^\t]*\t)*[\t]*$
。 CSV定义的复杂性的实际含义是(见上文)处理这些问题的工具相对缺乏,并且倾向于不相容,特别是在凌晨。
如果你给CSV和DTS启动,你有很好的select,其中之一是bcp.exe
。 这是非常快速和安全的,因为微软多年来一直没有试图更新它。 我不太了解DTS,但是如果你不得不使用它来实现自动化,IIRC有一种调用外部工具的方法。 但要小心, bcp.exe
不会将错误状态可靠地返回到shell。
如果您决定使用DTS并坚持使用CSV,那么真正最好的select是编写一个视图,为其准备相应的数据。 如果支持这个angular色,我会创build一个名为“DTS2012CSV”的模式,这样我就可以select * from DTS2012CSV.tablename
编写select * from DTS2012CSV.tablename
,给予任何关心战斗机会的人以理解它(因为你会logging它,你会不会在视图文字的评论?)。 如果需要的话,其他人可以复制其技术用于其他破碎的提取物。
HTH。
我知道这是两岁,但我现在也有这个问题,因为我们需要使用SQL Server 2008的合同,我们有(不要问)。 读完这个问题后,我意识到我需要做replacebuild议,但是当我去查询时,我遇到了截断问题,因为在查询中使用replace()函数会将文本转换为varchar(8000)默认情况下。
但是,我发现我可以在DB Source和Flat File对象之间使用Derived Column步骤做同样的事情。 例如,我有一个名为“short_description”的列可以引用它,所以我只是使用下面的函数作为expression式,并在派生列中select了“Replace short_description”
REPLACE(short_description,"\"","\"\"")
这似乎已经解决了我的问题。