我正在将excel数据导入到我的应用程序中的数据表中,并且遇到某些特定列值的问题。
Excel工作表列中的某些单元格 CustomerUniqID 会在角落显示带绿色标记的警告。
该数字的格式为文本或以撇号开头。
从Excel工作表填充数据集时,不会导入这些单元格值并显示空白值。
Dim query As String = "SELECT CINT(CustomerUniqID),[Status] FROM [Sheet1$]"
Dim conn As New OleDbConnection(conStr)
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Dim cmd As New OleDbCommand(query, conn)
Dim da As New OleDbDataAdapter(cmd)
Dim ds As New DataSet()
da.Fill(ds)
我的连接字符串是
<add name ="Excel07ConString" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=YES;IMEX=2'"/>
列 CustomerUniqID 包含数字,我无法导入这些单元格值。怎么做?
答案 0 :(得分:6)
原始帖子中描述的唯一可能让它失败的方法是,如果转义/文本单元格比我原来测试的更低。 OleDB不会在excel文件中使用Schema.ini
太糟糕了,因为这样可以提供一个非常简洁的解决方案,唉... ...
使用的样本数据:
Country Capital Population Rank
France Paris 2.25 7
Canada Toronto 2.5 6
Egypt Cairo 10.2 9
...
它实际上使用了16行,最后3个“Rank”项目被转义为文本(例如'2
)。这些都在Excel中显示绿色角落警告标志。
由于OleDB不读取/使用Schema,它会从前N行(在我的注册表中定义为8)中确定每列的数据类型。当转义的单元格与之匹配时,它将返回DBNull值。尝试通过SQL(CInt
,Val
)转换列失败,因为OleDB已经确定那里的数据不匹配,然后才能应用转换。
在某些情况下,我会两次阅读表格。首先将正确数据类型的“好”列合并为一个DataTable
;然后再次将“脏”列作为文本并手动转换数据。如果数据集中有其他数字列并且您不希望它们转换为文本/字符串,则此选项非常有用。
对于发布的案例,如果确实只涉及2列,您应该能够使用一个表作为文本读入;并添加一个数字列以接收转换后的值。而不是从一个表转换到另一个表,从一列转换到另一列。 (请问,如果你想要一个例子,但它只是以下的一部分)。
在任何一种情况下,“技巧”是使用不同的连接字符串来强制OleDB将数据作为文本读取。显然,这需要HDR=No
和IMEX=1
,至少我的配置是这样的:
Dim TextConStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\Temp\capitals.xls;Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"
此示例/文本代码使用2表方法验证其他数字(Population
)未转换,仅Rank
:
' ConStr to allow OleDB to guess the datatypes
Dim TypedConStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\Temp\capitals.xls;Extended Properties='Excel 8.0;HDR=Yes;IMEX=2';"
' ConStr to force OleDB to read it all as Text
Dim TextConStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\Temp\capitals.xls;Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"
' get the typed columns into a DT - skip Rank as dirty column
Dim SQL = "SELECT Country, Capital, Population FROM [Capitals$]"
Using con As New OleDbConnection(TypedConStr),
da As New OleDbDataAdapter(SQL, con)
dsPop.Tables.Add("Pop")
da.Fill(dsPop.Tables("Pop"))
End Using
' create a new temp DT containing just the naughty column
' use the generic F/Field index in the SQL (we told Ole there was no header)
SQL = "SELECT F4 As RankText FROM [Capitals$]"
' create connection forcing the contents to text:
Using con As New OleDbConnection(TextConStr),
da As New OleDbDataAdapter(SQL, con)
dsPop.Tables.Add("RankText")
da.Fill(dsPop.Tables("RankText"))
End Using
' remove the header row
dsPop.Tables("RankText").Rows.RemoveAt(0)
'create a new INT col in Dt(0)
dsPop.Tables("Pop").Columns.Add("Rank", GetType(Int32))
' convert Tbl(1) text to Int and store in Tbl(0)
For n As Integer = 0 To dsPop.Tables(1).Rows.Count - 1
dsPop.Tables("Pop").Rows(n).Item("Rank") =
Convert.ToInt32(dsPop.Tables("RankText").Rows(n).Item(0).ToString)
Next
'optional: remove the [RankText] tbl since we are done with it
dgv.DataSource = dsPop.Tables("Pop")
' report the datatype of the last row rank:
tbDataType.Text = dsPop.Tables("Pop").Rows(14).Item("Rank").GetType.ToString
在即时窗口中,报告的类型符合预期:
? dspop.Tables("Pop").Rows(0).Item(2) ' (population - paris)
2.25 {Double}
? dspop.Tables("RankText").Rows(0).Item(0) ' temp table text
"7" {String}
? dspop.Tables("Pop").Rows(0).Item(3) ' converted, merged value
7 {Integer}
对我来说,OleDB会自动将'3
转换为"3"
。换句话说,它在转换为文本时省略了前导tick /撇号。由于Excel版本和OleDB.ACE以及OleDb.Jet的组合可能会有很多可能性,我们可能需要一个后备转换器(我在意外地将返回标记添加到Excel后写了这个,也许它对某人有价值):
Private Function GetNumericValue(s As String) As Integer
' ToDo add exception handling
If Char.IsDigit(s(0)) Then
Return Convert.ToInt32(s)
Else
Return Convert.ToInt32(
New String(s.ToCharArray(1, s.Length - 1))
)
End If
End Function
它只会检查非数字的第一个字符,否则可能会将"1234 Main Street Suite 56"
转换为123456
,这可能是不可取的。结果:
俄罗斯,日本和葡萄牙是将Rank数据作为文本转义的行。
资源:
答案 1 :(得分:1)
我熟悉您正在谈论的此错误,&#34;该数字的格式为文本或以撇号开头。&#34;我在我的工作中使用了一个应用程序,它将所有数据存储为文本值,当我导出到excel时,每个数字字段都会发生这种情况。它与数据的基础类型有关。如果你输入一个数字(例如123)进入一个单元格(或者甚至进入数据库),这并不重要;重要的是它被解释为的类型。所以123&lt;&gt; &#34; 123&#34; (这是一个字符串)。 问题可能是您尝试加载数据的数据库具有数字类型的字段(例如int),但导入数据的程序不会将其识别为数字,而是文本值;因此,它正在抛出NULLS来补偿。
但在某些情况下这很好,例如,这些数字中的任何一个都有前导零吗?如果是这样,您可能希望将它们存储为文本值以保留前导零。如果没有,解决方法是(在excel 2010中)转到数据选项卡=&gt;文本到列,然后通过向导运行以获取正确的数据类型。这基本上解析了价值观。如果其他所有内容都正确加载,那么您的连接问题就不会出现问题。这应该可以直接在Excel中修复。
答案 2 :(得分:1)
答案 3 :(得分:1)
我遇到了同样的问题,几乎放弃了,但是我尝试了这个:
扩展属性= \“ Excel 12.0 Xml; HDR =是; IMEX = 1; ImportMixedTypes = Text; TypeGuessRows = 0 \”“;
成功了。 这是来自Jet.OLEDB的,但是它可以与ACE一起使用。
“检出位于[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Jet \ 4.0 \ Engines \ Excel]注册表REG_DWORD” TypeGuessRows“。这是不让Excel仅使用前8行来猜测列数据类型的关键。将此值设置为0以扫描所有行。这可能会损害性能。还请注意,添加IMEX = 1选项可能会导致IMEX功能仅在8行之后设置。请使用IMEX = 0来确保强制注册表TypeGuessRows = 0(扫描所有行)即可工作。”
答案 4 :(得分:0)
您的问题是对Excel的数据访问。 jet引擎通过前8行(或类似的行)解释列数据。因此,如果前8个单元格(不包括标题)是数字,则喷气引擎将采用该列的数字类型。与该数据类型不匹配的每个后续单元格将为NULL
。
您可以在此处找到更多信息:I need a workaround for Excel Guessing Data Types problem
答案 5 :(得分:0)
问题可能是由于您尝试将非数字值转换为整数值。对于表达式,如果我们使用以下表达式:= CInt(“ABC”),我们将在报告中获得#Error值。
请参阅下面的自定义代码以解决此问题:
Public Function Conv(ByVal A as String)
Dim B as string
Dim C as Integer
If isnumeric(A) Then
C=CInt(A)
Return C
else
B=CStr(A)
Return B
End If
End Function