2011-08-30 23 views
2

我正在處理用VB6編寫的遺留應用程序,它讀取Excel電子表格並將它們插入到數據庫中。
它可以工作,但如果電子表格中的數據沒有從第一行開始,則第一個數據行將被複制。
說,例如在電子表格中的第一3行是空白的,數據的前四列如下所示:如何防止VB6中的Microsoft ACE和JET複製Excel電子表格中第一行的數據?

_| A | B | C | D | E | F | G | 
1|  |  |  |  |  |  |  | 
2|  |  |  |  |  |  |  | 
3|  |  |  |  |  |  |  | 
4| 99 |Text1|Text2|Text3|Text4|Text5| 77 | 

應用程序連接到Excel電子表格和在使用以下代碼讀取它:

Public Function obtainConnectionExcel(sql_conn, uid) As Variant 
Dim cn As Object 

Set cn = CreateObject("ADODB.Connection") 
On Error Resume Next 

cn.Provider = "Microsoft.ACE.OLEDB.12.0" 
cn.Properties("Extended Properties").Value = "Excel 12.0;ReadOnly=True;HDR=No;IMEX=1" 

If (Err <> 0) Then 
    cn.Provider = "Microsoft.Jet.OLEDB.4.0" 
    cn.Properties("Extended Properties").Value = "Excel 8.0;ReadOnly=True;HDR=No;IMEX=1" 
End If 

On Error Resume Next 
cn.open getSpreadsheetPath(sql_conn, uid) 
Set obtainConnectionExcel = cn 
Exit Function 
End Function 
..... 
Public Function extractAllData(parameters) As String 

..... 'Variable declarations etc 
On Error Resume Next 
Set dbo_conn = obtainConnectionExcel(sql_conn, uid) 
If Err <> 0 Then 
    ....'logs error, goes to error handler 
End If 
On Error GoTo ErrorHandler 

If (dbo_conn.State = 1) Then 
    rownumber = 1 

    Do While rownumber <= numberOfRowsToGet 

     For x = lettercount To lettercount + lettercount_offset 

      letter = Chr(x) 
      sSql = "SELECT * FROM [" & worksheet & "$" & letter & rownumber & ":" & letter & rownumber & "]" 
      On Error Resume Next 
      Set rs = dbo_conn.execute(sSql) 

      If (Not rs.EOF) Then 
       'inserts the data into the db 
      End If 

     Next x 

     rownumber = rownumber + 1 
    Loop 

    .... 'Post processing 

Exit Function 

....'Error handlers 

End Function 

這應該是相關的代碼。發生在線路的問題:

sSql = "SELECT * FROM [" & worksheet & "$" & letter & rownumber & ":" & letter & rownumber & "]" 
     On Error Resume Next 
     Set rs = dbo_conn.execute(sSql) 

當數據被讀取,無論我們使用JET或ACE,數據返回是這樣的:

_| A | B | C | D | E | F | G | 
1| 99 |  |  |  |  |  | 77 | 
2| 99 |  |  |  |  |  | 77 | 
3| 99 |Text1|Text2|Text3|Text4|Text5| 77 | 
4| 99 |Text1|Text2|Text3|Text4|Text5| 77 | 

我曾嘗試連接到電子表格並以多種方式獲取數據,但似乎沒有任何工作 - 連接將失敗,或者數據只會是空值。
我找到了一些解決方法 - 例如,如果我在單元格A1中輸入空格字符,問題不再發生。但是,我想要一個基於程序的解決方案,而不是告訴用戶採取額外的步驟來避免這種情況。
它只複製第一行數據。如果單元格中的數據是一個數字,那麼它會將數據複製到該列上方的每個單元格中,如果它是文本,那麼它只會上升一個級別。
有趣的是,如果我改變電子表格來表示所有的數據都是文本,那麼它就會複製每個單元格,就好像它們是數字一樣(即在上面的每個單元格中,而不是單個單元格中)

總而言之,這是相當令人生氣的 - 因爲我在搜索這個問題時沒有任何運氣,所以我只能斷定我們做錯了什麼,或者很少有人對這種類型的測試數據感到困擾。

[編輯]經過一番調查我解決了這個已經取得了一些進展 - 「提供者假定你的數據表最上面,最左邊的非空指定工作表上的細胞開始」 (http://support.microsoft.com/default.aspx?scid=kb;en-us;257819)。如果我使用語句來選擇整個工作表,這是確認 - 它只返回數據塊。
因此,當我選擇任何超出該範圍的單元格時,提供程序(而不是像返回空值這樣明智的操作)將從該特定列的最上面的非空單元格返回數據。
我可以假設地改變系統,以便它抓住所有的數據,並假定最上面最左邊的單元格是單元格A1,但這會破壞已經存在的數據的兼容性。
我現在需要的是一種獲取返回數據的單元格引用的方式,所以我可以適當地對待它,或者強制它不再發生。

+0

你可以添加調試語句記錄字符串'sSql'到一個文件(或打印或其他)每個迭代?查看您在問題中提供的每個測試行的SQL是多少有用的。 – jmtd

+0

好吧,我不打算列出所有的(大約1250個語句),但是在我使用的測試示例中,它們是這樣的:'SELECT * FROM [Sheet1 $ A1:A1]'直到' SELECT * FROM [Sheet1 $ Z1:Z1]',然後它轉到'SELECT * FROM [Sheet1 $ A2:A2]'並重復。 – Aradiel

+0

好的,所以您對電子表格的每個* Cell *有一個SQL查詢?查詢後「rs」的值是多少?你可以檢查它,看看它是否是空字符串,如果是,跳過該行的其餘部分? – jmtd

回答

0

回答我自己的問題:看起來你不能。但是,您可以嘗試對問題進行編碼。

JET和ACE提供程序都將最上面最左側的非空單元視爲數據集的開始(http://support.microsoft.com/default.aspx?scid=kb;en-我們; 257819) 因此,當您嘗試從數據集開始之前發生的單元格中獲取值時,而不是做一些明智的事情並返回null,則提供程序將返回基於最上面一行數據的猜測。

我找不到任何方式來獲得供應商返回的數據集的單元格引用 - 它標記一切,F1,F2等(「字段1」,「字段2」)

所以有剩下的兩個解決方案:

1)一次抓取整個數據集,假設數據從A1開始,並使用該假設將其插入到數據庫中。 這不幸的是會導致與預先存在的數據相沖突。

2)以編程方式確定單元格引用,並正確輸入數據。 我這樣做是使用下面的縮寫代碼

sSql = "SELECT * FROM [" & worksheet & "$]" 
Set rs = dbo_conn.execute(sSql) 

rownumber = 1 
If Not rs.EOF Then 
    oledata_array = rs.GetRows() 
Else 
    ReDim oledata_array(0, 0) 
End If 

Do While rownumber <= numberOfRowsToGet 
    col_number = 1 
    For x = lettercount To lettercount + lettercount_offset 

     letter = Chr(x) 
     sSql = "SELECT * FROM [" & worksheet & "$" & letter & rownumber & ":" & letter & rownumber & "]" 
     On Error Resume Next 
     Set rs = dbo_conn.execute(sSql) 
     If Not rs.EOF Then 
      If rs(0) <> "" Then 
       If x < furthest_left Then 
        furthest_left = x 
       End If 
       If x > furthest_right Then 
        furthest_right = x 
       End If 
       If rownumber > bottom_of_set Then 
        bottom_of_set = rownumber 
       End If 
      Else 
      End If 
     End If 

     col_number = col_number + 1 

    Next x 

    rs.MoveNext 
    rownumber = rownumber + 1 
Loop 
rs.Close 

top_of_set = bottom_of_set - UBound(oledata_array, 2) 

If CLng(UBound(oledata_array, 1)) <> CLng(furthest_right - furthest_left) Then 
    'log the fact that there is a discrepency, and continue 
End If 

'now have the co-ords of the "square" of data as it occurs in the spreadsheet 

rownumber = 1 
row_index = 0 
Do While rownumber <= numberOfRowsToGet 
    col_number = 1 
    For x = lettercount To lettercount + lettercount_offset 

     letter = Chr(x) 

     'construct the first chunk of the sql insert string 

     If (x <= furthest_right) And (x >= furthest_left) And (rownumber <= bottom_of_set) And (rownumber >= top_of_set) Then 
      sSql = sSql & "'" & oledata_array(col_number - 1, row_index) & "'" 
      col_number = col_number + 1 
     Else 
      sSql = sSql & "''" 
     End If 

     'finish the sql string and execute 

    Next x 
1

一個流行的博客文章和線程(最初由OneDayWhen)提供了一個類似於您的問題,提到了註冊表調整,它改變了Excel猜測單元格數據類型的方式。

我相信這種「猜測」行爲可能是您的問題的根源。

External Data - Mixed Data Types

總之,使用TypeGuessRows獲得射流以檢測「混合 類型」的情況是否存在,或用它來「特技」射流成檢測 certaint數據類型爲大多數類型。如果檢測到 「混合類型」情況,請使用ImportMixedTypes通知 Jet以使用多數類型或強制所有值爲「文本」 (最多255個字符)。

其他討論修改您的連接字符串以包含MaxScanRows = 0但這似乎不能解決問題。我瞭解您可能正在尋找便攜式解決方案,但我無法找到這樣的解決方法。

+0

這是連接字符串中的IMEX = 1與IMEX = 2開關。 IMEX = 1不會猜測數據類型,而IMEX = 2會。後者是默認值。爲了在Excel中解決這個問題,我總是在FROM子句中爲連接字符串編寫一個SQL SELECT語句和一個IN子句。這樣,您不必更改註冊表。 –

+0

大衛是正確的 - 連接字符串的IMEX = 1部分是爲了強制它假設一切都是文本。不幸的是,鏈接到網站dirdev是相當古老 - 我的機器有不同的註冊表結構,雖然開發機器有一個匹配網站(也是我自己的)。在問題依然存在的開發機器上,ImportMixedTypes註冊表項被設置爲「文本」,除了名爲「文本」的文件夾外,其他所有內容都足夠奇怪。按照文件夾命名慣例,我認爲這是一個單獨的程序。 – Aradiel

+0

我永遠不會改變註冊表 - 我只是在連接字符串中使用IMEX = 1,因此無需在註冊表中修改該問題。 –

相關問題