Mar*_*ith 9 sql-server azure-sql-database encoding openrowset
我有一个包含以下内容的示例数据文件,并使用 UTF8 编码保存。
\noab~opqr\n\xc3\xb6ab~\xc3\xb6pqr\n\xc3\xb6ab~\xc3\xb6pqr\nRun Code Online (Sandbox Code Playgroud)\n该文件的格式是固定宽度,第 1 至第 3 列各分配 1 个字符,第 4 列保留 5 个字符。
\n我创建了一个 XML 格式文件,如下所示
\n<?xml version = "1.0"?> \n<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> \n <RECORD> \n <FIELD xsi:type="CharFixed" ID="Col1" LENGTH="1"/> \n <FIELD xsi:type="CharFixed" ID="Col2" LENGTH="1"/> \n <FIELD xsi:type="CharFixed" ID="Col3" LENGTH="1"/> \n <FIELD xsi:type="CharFixed" ID="Col4" LENGTH="5"/> \n <FIELD xsi:type="CharTerm" ID="LINE_BREAK" TERMINATOR="\\n"/> \n </RECORD> \n <ROW> \n <COLUMN SOURCE="Col1" NAME="Col1" xsi:type="SQLNVARCHAR"/> \n <COLUMN SOURCE="Col2" NAME="Col2" xsi:type="SQLNVARCHAR"/> \n <COLUMN SOURCE="Col3" NAME="Col3" xsi:type="SQLNVARCHAR"/> \n <COLUMN SOURCE="Col4" NAME="Col4" xsi:type="SQLNVARCHAR"/> \n </ROW> \n</BCPFORMAT>\nRun Code Online (Sandbox Code Playgroud)\n令人失望的是运行以下 SQL...
\nSELECT *\nFROM OPENROWSET\n(\nBULK 'mydata.txt',\nFORMATFILE = 'myformat_file.xml',\nCODEPAGE = '65001'\n) AS X\nRun Code Online (Sandbox Code Playgroud)\n产生以下结果
\nCol1 Col2 Col3 Col4\n---- ---- ---- -----\no a b ~opqr\n\xef\xbf\xbd \xef\xbf\xbd a b~\xc3\xb6p\n\xef\xbf\xbd \xef\xbf\xbd a b~\xc3\xb6p\nRun Code Online (Sandbox Code Playgroud)\n由此我得出结论,LENGTH计算的是字节而不是字符。
有什么办法可以让这个工作在UTF8 编码的固定字符宽度下正常工作吗?
\n(目标环境是从 Blob 存储读取的 Azure SQL 数据库)
\n注意:评论中建议添加COLLATION="LATIN1_GENERAL_100_CI_AS_SC_UTF8"元素FIELD可能会有所帮助,但结果保持不变。
一种解决方法是仅更改格式文件以批量导入整行,并在 TSQL 中进行子字符串化
带格式文件
<?xml version = "1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD xsi:type="CharTerm" ID="WholeLine" TERMINATOR="\n"/>
</RECORD>
<ROW>
<COLUMN SOURCE="WholeLine" NAME="WholeLine" xsi:type="SQLNVARCHAR"/>
</ROW>
</BCPFORMAT>
Run Code Online (Sandbox Code Playgroud)
以下确实返回了期望的结果
SELECT SUBSTRING(WholeLine, 1,1) AS Col1,
SUBSTRING(WholeLine, 2,1) AS Col2,
SUBSTRING(WholeLine, 3,1) AS Col3,
SUBSTRING(WholeLine, 4,5) AS Col4
FROM OPENROWSET
(
BULK 'mydata.txt',
FORMATFILE = 'myformat_file.xml',
CODEPAGE = '65001'
) AS X
Run Code Online (Sandbox Code Playgroud)
由此我得出结论,
LENGTH计算的是字节而不是字符。
这是正确的,但没有办法将其改为字符。
这种情况类似于char( n )、varchar( n )、nchar( n ) 和 nvarchar( n ) 中的 n ,其中“ n ”表示字节数,而不是字符数。请参阅文档:
一个常见的误解是认为 CHAR(n) 和 VARCHAR(n),n 定义字符数。但在 CHAR(n) 和 VARCHAR(n) 中,n 定义以字节为单位的字符串长度 (0-8,000)。n 从不定义可以存储的字符数。这与 NCHAR(n) 和 NVARCHAR(n) 的定义类似。产生这种误解是因为使用单字节编码时,CHAR和VARCHAR的存储大小为n个字节,字符数也是n。但是,对于 UTF-8 等多字节编码,较高的 Unicode 范围 (128-1,114,111) 会导致一个字符使用两个或更多字节。
这让许多人感到困惑,尤其是自从引入UTF-8 支持之后。以前使用 n(var)char 和增补字符是可能的,但我想说相对很少遇到。
如果 SQL Server将来在多个领域(包括 OPENROWSET)扩展对字符而不是字节的支持,那就太好了。
与此同时,我也可能会使用您的解决方法。
| 归档时间: |
|
| 查看次数: |
3030 次 |
| 最近记录: |