2012-05-04 58 views
0

我期待在Excel中的單個單元格內執行SQL SELECT語句,並使用其他單元作爲SELECT語句的輸入。經過一番搜索之後,我發現sql.request函數可以完成我正在尋找的任務。但是,該功能在2002年後不推薦使用,我在這裏運行Excel 2007和2010。 CitationSQL.REQUEST Excel函數替代?用VBA創建一個?

我試圖創建一個宏/ VBA腳本來做同樣的事情,但一直沒有能夠得到它很遠。我在LabVIEW,Mathematica和SQL中完成所有的編程工作;我不知道VBA中發生了什麼。這是我已經設法想出:

Sub Test2() 

' Declare the QueryTable object. I'm not actually sure why this line is here... 
Dim qt As QueryTable 

' Set up the SQL Statement 
sqlstring = "SELECT `Substrate ID` FROM temp_table WHERE `id`=" & Range("A1").Value 

' Set up the connection string, reference an ODBC connection 
connstring = "ODBC;DSN=OWT_x64;" 

' Now implement the connection, run the query, and add 
' the results to the spreadsheet 
With ActiveSheet.QueryTables.Add(Connection:=connstring, Destination:=Range("A22"), Sql:=sqlstring) 
    .Refresh BackgroundQuery:=False 
End With 

End Sub 

有與上面的代碼三個主要問題:

  1. 這段代碼在小區A22返回列ID(「襯底ID」) ,以及單元格A23中的SQL查詢的結果。我只想要結果,而我只希望它在單元格A22中。所有查詢都只能返回1行1列。
  2. 我不知道如何製作它,以便輸出單元格A22是腳本運行時任何單元格處於活動狀態。另外,輸入單元格A1應該是直接位於活動單元格左側(第1列)的單元格。
  3. 我不知道如何把它變成一個Excel函數

    =sql.request(connection_string,[output_ref],[driver_prompt],[query_text],[col_names_logical])

    這是我的最終目標。這樣,我可以將此代碼提供給我公司的其他人,並且他們可以輕鬆使用它。

連接是到MySQL 5.6數據庫的ODBC連接。該查詢非常簡單,並沿着以下幾行:

SELECT column FROM table WHERE id=excel_cell_value 

正如您從VBA代碼中可以看到的那樣。

目前,我在不同的Excel工作表中運行查詢,返回「id」和「Substrate ID」列的所有行,然後運行VLOOKUP以查找感興趣的項目。隨着我們的數據庫規模增長很快,這開始成爲一個問題。

那麼,請問:

  1. 我怎樣才能在結果擺脫列ID的?
  2. 我怎樣才能把它變成一個自定義的Excel函數?我看過Office.com,這看起來不太難,但我需要一個工作腳本。
  3. - 或者 - 有沒有人已經提出了他們願意分享的自定義函數?

謝謝!

編輯:管理得到的東西工作感謝蒂姆的鏈接。

Function SQLQuery(sqlString As String, connString As String, Optional TimeOut As Integer) As String 

SQLQuery = Error 'Assume an error happened 

Dim conn As ADODB.Connection 
Dim record As ADODB.Recordset 

Set conn = New ADODB.Connection 
conn.ConnectionString = connString 
conn.Open 
Set record = New ADODB.Recordset 

If TimeOut > 0 Then 
    conn.CommandTimeout = TimeOut 
End If 

record.Open sqlString, conn 

Dim cols As Long 
Dim i As Long 

cols = record.Fields.Count 'Count how many columns were returned 
If Not record.EOF Then 'Put results into comma-delimited string 
    record.MoveFirst 
    s = "" 
    If Not record.EOF Then 
     For i = 0 To cols - 1 
      s = s & IIf(i > 0, ",", "") & record(i) 
     Next i 
    End If 
End If 

SQLQuery = s 

End Function 

然而,它很慢。任何想法如何加快它?

+0

http://itknowledgeexchange.techtarget.com/beyond-excel/using-ado-to-read-a-database/演示如何使用ADO在Excel –

+0

來創建用戶定義的函數(UDF)由於提供了Tim提供的鏈接,我設法做了一些工作。 (請參閱編輯)但是,在多個單元格上運行時速度很慢。任何人都知道如何解決該問題? – dthor

+0

一次運行一個單元的UDF永遠不會像通過一次更新所有單元的子查詢一樣快:您每次UDF重新計算時都會創建,打開和關閉連接(可能更多比每張紙/工作簿重新計算一次)。您可以嘗試在函數內的靜態變量中緩存連接(和連接字符串),因此如果下一次調用使用相同的連接字符串,則不必建立新的連接。儘管我從來沒有嘗試過。 –

回答

1

下面是緩存連接的快速測試。在一個包含100個查找的測試工作表上,它將計算時間從大約18秒縮短到大約0.5秒

請記住,它會保持連接打開,直到您關閉Excel(或重置VB環境)。

如果你想測試你的環境的差異,你可以註釋掉標出的行(不要忘記在VBE中按「停止」按鈕來清除靜態變量)。

Function SQLQuery(sqlString As String, connString As String, _ 
            Optional TimeOut As Integer) As String 

    Static cs As String 
    Static conn As ADODB.Connection 

    SQLQuery = Error 'Assume an error happened 
    Dim s 

    If conn Is Nothing Or connString <> cs Then 
     Set conn = New ADODB.Connection 
     conn.ConnectionString = connString 
     conn.Open 
     If TimeOut > 0 Then conn.CommandTimeout = TimeOut 
     cs = connString '###comment this out to disable caching effect 
    End If 

    Dim record As New ADODB.Recordset 

    record.Open sqlString, conn 

    Dim cols As Long 
    Dim i As Long 

    cols = record.Fields.Count 'Count how many columns were returned 
    If Not record.EOF Then 'Put results into comma-delimited string 
     record.MoveFirst 
     s = "" 
     If Not record.EOF Then 
      For i = 0 To cols - 1 
       s = s & IIf(i > 0, ",", "") & record(i) 
      Next i 
     End If 
    End If 

    SQLQuery = s 

End Function 
+0

啊,現在真是太棒了!這絕對更有用。謝謝蒂姆! – dthor