![](/img/trans.png)
[英]How do I write one query to get data from multiple tables containing similar name in SQL Server
[英]How do I write data from access tables to excel
我正在遍歷一個名為_TF_Tables
的表,該表包含數據庫中需要為其創建 Excel 工作簿並填充該表中的數據的所有表的名稱。
當我逐行瀏覽腳本時,以下內容在調試模式下工作。 它創建一個空的 excel 文件,添加一個帶有表格名稱的新工作表,並使用表格名稱保存工作簿。
然后它查詢表中的所有數據並將其寫入新創建的 Excel 文件。
當我運行腳本時出現問題(不是在調試模式下)。 它在以下行給出錯誤:
adoConnnectionTF.Execute(strQuery)
錯誤
System.Runtime.InteropServices.COMException:'Microsoft Access 數據庫引擎找不到對象'TF_TT'。 確保對象存在並且正確拼寫其名稱和路徑名。 如果“TF_TT”不是本地對象,請檢查您的網絡
Dim recordSetTables As Access.Dao.Recordset = dbTFFrom.OpenRecordset("_TF_Tables", Access.Dao.RecordsetTypeEnum.dbOpenDynaset)
Dim Excel As Object
Dim tempTableName As String
Dim xlWorkSheet As Object
Dim strQuery As String
Do Until recordSetTables.EOF
tempTableName = recordSetTables.Fields(0).Value
Excel = CreateObject("Excel.Application")
xlWorkSheet = Excel.workbooks.add
xlWorkSheet.SaveAs("path\" & tempTableName & ".xlsx")
xlWorkSheet = Nothing
Excel.quit()
Excel = Nothing
strQuery = "SELECT * INTO [Excel 8.0;HDR=YES;DATABASE=path\" & tempTableName & ".xlsx].[" & tempTableName & "] FROM [" & tempTableName & "];"
adoConnnectionTF.Execute(strQuery)
recordSetTables.MoveNext()
Loop
recordSetTables.Close()
recordSetTables = Nothing
strQuery 的輸出:
"SELECT * INTO [Excel 8.0;HDR=YES;DATABASE=path\TF_BLA.xlsx].[TF_BLA] FROM [TF_BLA];"
它會創建 1 個有時 2 個填充數據的 Excel 文件,但最終會出錯。 因為它不是一直為同一張桌子拋出的,所以很難理解
以上只是我將所需表格寫入 Excel 文件的嘗試。 替代解決方案也可以。
編輯 1
正如評論中所建議的,我將記錄集更改為 DAO(之前是 ADO),但是錯誤仍然存在。
編輯 2
正如評論中所建議的,將 Dim 語句置於循環之外,縮短了代碼並提供了strQuery
的輸出
編輯 3 / 解決方案
我找到了解決方案。 以下從訪問文件中的表創建所需的 excel 文件
Dim dbTFFromAs Access.Dao.Database = workSpace.OpenDatabase(pathToTF)
Dim recordSetTables As Access.Dao.Recordset = dbTFFrom.OpenRecordset("_TF_Tables", Access.Dao.RecordsetTypeEnum.dbOpenDynaset)
Dim tempTableName As String
Dim strQuery As String
Do Until recordSetTables.EOF
tempTableName = recordSetTables.Fields(0).Value
strQuery = "SELECT * INTO [Excel 12.0 Xml;HDR=YES;DATABASE=\\DADI\MD\MDatabases\ExportedData\TT\" & tempTableName & ".xlsx].[" & tempTableName & "] FROM [" & tempTableName & "];"
adoConnnectionTF.Execute(strQuery)
recordSetTables.MoveNext()
Loop
recordSetTables.Close()
recordSetTables = Nothing
下面展示了如何使用 OLE DB 從 Access 數據庫中讀取數據並使用 Excel Interop 將其插入 Excel 工作簿。 它已經過 Access 2016 和 Excel 2016 的測試。
先決條件:
注意:您可以考慮使用以下 NuGet 包之一,而不是使用 Excel 互操作: DocumentFormat.OpenXml (另請參見:此處)、 ClosedXML或EPPlus 。 可能還有其他可用的。
添加參考
創建一個類(名稱:Helper.vb)
注意:檢查下面代碼中的“ToDo”項。 您需要將 Select 語句中的列名( SELECT tblName FROM _TF_TABLES order by tblName
)替換為正確的列名。 此處定義的順序將決定工作表在 Excel 工作簿中的創建順序,以及工作表選項卡的順序。 此外,可能需要更改用於 Access 數據庫的連接字符串。 有關詳細信息,請參閱連接字符串。
Imports System.Data.OleDb
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Helper
Private _connectionStringACE As String = String.Empty
Private _connectionStringAceJet As String = String.Empty
Private _connectionStringJet As String = String.Empty
Public Sub New(filename As String)
'ToDo: replace with connection string for the version that you're using
'set value
_connectionStringACE = String.Format("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0};Persist Security Info=False;", filename)
_connectionStringAceJet = String.Format("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0};Jet OLEDB:Database Password=''", filename)
_connectionStringJet = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};User Id=admin;Password=;", filename)
End Sub
Public Sub New(filename As String, password As String)
'ToDo: replace with connection string for the version that you're using
'set value
_connectionStringAceJet = String.Format("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = {0};Jet OLEDB:Database Password={1}", filename, password)
_connectionStringJet = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};User Id=admin;Password={1};", filename, password)
End Sub
Public Function AccessGetTables() As DataTable
'get all Access tables including system tables
Dim dt As DataTable = New DataTable()
Using con As OleDbConnection = New OleDbConnection(_connectionStringAceJet)
'open
con.Open()
'get Access tables
dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)
Return dt
End Using
End Function
Private Function AccessGetDataFromSpecifiedTable(sqlText As String) As DataTable
'get data from Access database
Dim dt As DataTable = New DataTable()
Debug.WriteLine($"sqlText: {sqlText}")
Using con As OleDbConnection = New OleDbConnection(_connectionStringAceJet)
'open
con.Open()
Using da As OleDbDataAdapter = New OleDbDataAdapter(sqlText, con)
'get data
da.Fill(dt)
Return dt
End Using
End Using
End Function
Public Function AccessGetUserTables() As List(Of String)
'get list of tables that were user created
Dim userTables As List(Of String) = New List(Of String)
'get Access tables
Dim dt As DataTable = AccessGetTables()
If dt IsNot Nothing AndAlso dt.Rows.Count > 0 Then
For Each row As DataRow In dt.Rows
'Debug.WriteLine($"{row("TABLE_NAME"),-25} {row("TABLE_TYPE"),25}")
If row("TABLE_TYPE") IsNot DBNull.Value AndAlso row("TABLE_TYPE") IsNot Nothing AndAlso row("TABLE_TYPE").ToString() = "TABLE" Then
'add
userTables.Add(row("TABLE_NAME").ToString())
End If
Next
End If
Return userTables
End Function
Public Function ExcelCreateWorkbook(filename As String) As String
Dim oMissing As Object = System.Reflection.Missing.Value
Dim excelApp As Excel.Application = Nothing
Dim excelWorkbook As Excel.Workbook = Nothing
Dim excelWorksheet As Excel.Worksheet = Nothing
Try
'get data from _TF_TABLES
'ToDo: replace 'tblName' with correct column name(s)
Dim dtTfTables As DataTable = AccessGetDataFromSpecifiedTable("SELECT tblName FROM _TF_TABLES order by tblName")
'if no data was found, throw an exception
'ToDo: if desired, return an error message instead
If dtTfTables Is Nothing OrElse dtTfTables.Rows.Count = 0 Then
Throw New Exception("Error: No data was found.")
End If
'create New instance
excelApp = New Excel.Application()
'set Excel visability
excelApp.Visible = True
'suppress displaying alerts (such as prompting to overwrite existing file)
excelApp.DisplayAlerts = False
'disable user control while modifying the Excel Workbook
'to prevent user interference
'only necessary if Excel application Visibility property = true
'excelApp.UserControl = False
'add workbook
excelWorkbook = excelApp.Workbooks.Add()
'used to keep track of previous Worksheet
Dim previousWorksheet As Excel.Worksheet = Nothing
If excelWorkbook IsNot Nothing AndAlso excelWorkbook.Sheets.Count > 0 Then
'set value
previousWorksheet = CType(excelWorkbook.Sheets("Sheet1"), Excel.Worksheet)
End If
'loop for each table name found in _TF_TABLES
For Each rowTf As DataRow In dtTfTables.Rows
If rowTf(0) IsNot Nothing AndAlso rowTf(0) IsNot DBNull.Value Then
'add a worksheet And set the value to the New worksheet
excelWorksheet = CType(excelWorkbook.Sheets.Add(After:=previousWorksheet), Excel.Worksheet)
'set name
excelWorksheet.Name = rowTf(0).ToString()
'get data from specified table
Dim dt As DataTable = AccessGetDataFromSpecifiedTable($"SELECT * FROM {rowTf(0).ToString()}")
If dt IsNot Nothing AndAlso dt.Rows.Count > 0 Then
Debug.WriteLine($"Adding column headers for table: {rowTf(0).ToString()}")
'add column headers
For colIndex As Integer = 0 To dt.Columns.Count - 1
'indices are 1-based in Excel; A1 = Cells(1,1)
excelWorksheet.Cells(1, colIndex + 1) = dt.Columns(colIndex).ColumnName
Next
Debug.WriteLine($"Adding data for table: {rowTf(0).ToString()}")
Dim rowNum As Integer = 1
For Each rowDt As DataRow In dt.Rows
'increment
rowNum += 1
For colIndex As Integer = 0 To dt.Columns.Count - 1
Debug.WriteLine($" rowNum: {rowNum}; colNum: {colIndex + 1}")
'indices are 1-based in Excel; A1 = Cells(1,1)
excelWorksheet.Cells(rowNum, colIndex + 1) = rowDt(colIndex)
Next
Next
End If
'set value
previousWorksheet = excelWorksheet
End If
Next
If excelWorkbook IsNot Nothing AndAlso excelWorkbook.Sheets.Count > 0 Then
excelWorksheet = CType(excelWorkbook.Sheets("Sheet1"), Excel.Worksheet)
'delete existing worksheet
excelWorksheet.Delete()
End If
If excelApp IsNot Nothing AndAlso excelWorkbook IsNot Nothing Then
'save Workbook - if file exists, overwrite it
excelWorkbook.SaveAs(filename, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value)
End If
Catch ex As Exception
Debug.WriteLine("Error (ExcelCreateWorkbook): " & ex.Message)
Throw ex
Finally
If excelWorkbook IsNot Nothing Then
excelWorkbook.Close()
'release resource
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelWorkbook)
excelWorkbook = Nothing
End If
If excelWorksheet IsNot Nothing Then
'release resource
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelWorksheet)
excelWorksheet = Nothing
End If
If excelApp IsNot Nothing Then
excelApp.Quit()
'release all resources
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excelApp)
End If
End Try
Return $"Created Excel Workbook: '{filename}'"
End Function
End Class
用法(創建 Excel 工作簿)
Private _helper As Helper = Nothing
...
Private Sub btnCreateExcelWorkbook_Click(sender As Object, e As EventArgs) Handles btnCreateExcelWorkbook.Click
Using ofd As OpenFileDialog = New OpenFileDialog()
ofd.Filter = "Access Files (*.accdb)|*.accdb|All Files (*.*)|*.*"
ofd.Title = "Choose Access Filename"
If ofd.ShowDialog() = DialogResult.OK Then
Using sfd As SaveFileDialog = New SaveFileDialog()
sfd.Filter = "Excel File (*.xlsx)|*.xlsx|All Files (*.*)|*.*"
sfd.FileName = "Test_TFTables.xlsx"
sfd.Title = "Choose Excel Filename"
If sfd.ShowDialog() = DialogResult.OK Then
'create new instance
_helper = New Helper(ofd.FileName)
'create Excel file
Dim result As String = _helper.ExcelCreateWorkbook(sfd.FileName)
Debug.WriteLine($"{result}")
End If
End Using
End If
End Using
End Sub
用法(從 Access 獲取表名)
Private _helper As Helper = Nothing
...
Private Sub btnGetAccessTables_Click(sender As Object, e As EventArgs) Handles btnGetAccessTables.Click
Using ofd As OpenFileDialog = New OpenFileDialog()
ofd.Filter = "Access Files (*.accdb)|*.accdb|All Files (*.*)|*.*"
ofd.Title = "Choose Access Filename"
If ofd.ShowDialog() = DialogResult.OK Then
'create new instance
_helper = New Helper(ofd.FileName)
Dim userTables As List(Of String) = _helper.AccessGetUserTables()
For Each tbl In userTables
Debug.WriteLine(tbl)
Next
End If
End Using
End Sub
這是用於測試的 Access 表定義(和一些數據):
_TF_TABLES :
表 123 :
表 456 :
表 789 :
資源
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.