Read Multiple Excel Sheets in a Listview - excel

I am trying to read an excel file that has multiple sheets 1,2,3,4,5,6,7,8,9,10
I need to read several columns of what is in those sheets for example from the range a1: a20 and c1: c20
The result is listing it in a listview, I am trying with several suggestions that appear in the forum, but it only allows me to read one sheet and I need to read several at the same time. Anyway I put the code that I am using.
Thanks in advance
Public Class Frm_ImportarLibro
Public Function Obtenerdatos(ByVal ruta As String, ByVal hoja As String, ByVal rango As String) As DataTable
Dim cadenaConexion As String = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='Excel 8.0;HDR=NO';" &
"Data Source=" & ruta
Using cnn As New OleDbConnection(cadenaConexion)
Dim cmd As OleDbCommand = cnn.CreateCommand()
cmd.CommandText = String.Format("SELECT * FROM [{0}${1}]", hoja, rango)
Dim da As New OleDbDataAdapter(cmd)
Dim dtTemp As New DataTable("Prueba")
da.Fill(dtTemp)
Dim dt As DataTable = dtTemp.Clone()
Dim rows As DataRow() = dtTemp.Select()
For index As Integer = 0 To rows.Count - 1
Dim row As DataRow = rows(index)
If (row.Item(0) Is DBNull.Value) Then
Exit For
End If
dt.ImportRow(row)
Next
Return dt
End Using
End Function

I believe this would be a matter of looping through the sheets and loading a DataTable for each sheet which is then added to a DataSet. My code assumes that the same range is used for each sheet. I made the range contiguous because it would require a separate command for each non-contiguous range. I believe it would be easier to ignore the extraneous data in the resulting DataTable.
Private cadenaConexion As String = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='Excel 8.0;HDR=NO';Data Source="
Private rango As String = "A1:C20"
Private Function GetXLSheetNames(path As String) As List(Of String)
Dim SheetNames As New List(Of String)
Dim dt As DataTable
Using cn As New OleDbConnection(cadenaConexion & path)
cn.Open()
dt = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)
End Using
For Each row As DataRow In dt.Rows
Dim s = row("Table_Name").ToString
SheetNames.Add(s)
Next
Return SheetNames
End Function
Public Function Obtenerdatos(ByVal ruta As String, ByVal hoja As String, ByVal rango As String) As DataSet
Dim ds As New DataSet
Dim lst = GetXLSheetNames(ruta)
Using cnn As New OleDbConnection(cadenaConexion & ruta),
cmd As New OleDbCommand()
cmd.Connection = cnn
cnn.Open()
For Each s In lst
Dim dt As New DataTable(s)
cmd.CommandText = $"SELECT * FROM [{s}{rango}]"
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
ds.Tables.Add(dt)
Next
End Using
Return ds
End Function

Related

Exception Visual Basic .NET Clipboard Text to Excel Via Interop/Worksheet.Paste()

Trying to get an older VB.NET application working again. One feature builds a text string composed of text delimited by Tab/Return characters, then creates (via interop) an Excel Workbook, adds a Worksheet, and (desired) paste the text string into the worksheet.
Here is the code:
Private Function AddNewWorksheetToWorkbook(
ByVal theWorkbook As Workbook,
ByVal worksheetName As String,
ByVal textToPaste As String
) As Microsoft.Office.Interop.Excel.Worksheet
Dim newWorksheet As Microsoft.Office.Interop.Excel.Worksheet
newWorksheet = theWorkbook.Worksheets.Add()
newWorksheet.Name = worksheetName
theWorkbook.Save()
newWorksheet.Activate() 'All works fine, file saved, worksheet named and Active as desired
Dim app As Microsoft.Office.Interop.Excel.Application
app = newWorksheet.Application
If app.ActiveSheet.Name = newWorksheet.Name Then 'Just a test to make sure ActiveSheet is the one desired -- it is
Clipboard.SetText(textToPaste) 'Clipboard has text delimited by vbTab and vbReturn (a "plain" text table)
newWorksheet.Range("A1").Select() 'Cell "A1" is properly selected
newWorksheet.Paste() 'BOOM! Get System.Runtime.InteropServices.COMException: 'Microsoft Excel cannot paste the data.'
End If
theWorkbook.Save()
Return newWorksheet
End Function
As noted in the comments, all goes well until the Worksheet.Paste() method call.
I have tried variations on Paste() as well as PasteSpecial(), etc. No joy.
Keep getting System.Runtime.InteropServices.COMException: 'Microsoft Excel cannot paste the data.'
I am able to (manually, not through interop) click "Paste" in Excel and it works just fine.
I would be grateful for any insights from the stackoverflow community!
So, here is what I ended up doing to solve (actually avoid and solve) the problem I was facing. Here is how I altered the existing function.
Private Function AddNewWorksheetToWorkbook(
ByVal theWorkbook As Workbook,
ByVal worksheetName As String,
ByVal textToPaste As String
) As Microsoft.Office.Interop.Excel.Worksheet
Dim newWorksheet As Microsoft.Office.Interop.Excel.Worksheet
newWorksheet = theWorkbook.Worksheets.Add()
newWorksheet.Name = worksheetName
theWorkbook.Save()
newWorksheet.Activate() 'All works fine, file saved, worksheet named and Active as desired
Dim app As Microsoft.Office.Interop.Excel.Application
app = newWorksheet.Application
If app.ActiveSheet.Name = newWorksheet.Name Then
Dim rowCount As Integer = 0
Dim colCount As Integer = 0
Dim values(,) As String = ExtractTwoDimDataSet(pasteText, rowCount, colCount)
Dim oRange As Range
oRange = newWorksheet.Range(newWorksheet.Cells(1, 1), newWorksheet.Cells(rowCount, colCount))
oRange.Value = values
End If
theWorkbook.Save()
Return newWorksheet
End Function
The change, of course, is to not use the Clipboard at all (which users might appreciate) and assign the "two-dimensional" text array to a Cell range on the Worksheet. The function (yes, I know, ugly with return values and ByRef parameters) is as follows:
Private Shared Function ExtractTwoDimDataSet(tabAndCrLfDelimitedText As String, ByRef rowCount As Integer, ByRef colCount As Integer) As String(,)
rowCount = 0
colCount = 0
Dim rows() As String
Dim columns() As String
rows = Split(tabAndCrLfDelimitedText, vbCrLf)
rowCount = rows.Length
For Each line As String In rows
columns = Split(line, vbTab)
If columns.Length > colCount Then
colCount = columns.Length
End If
Next
Dim values(rowCount, colCount) As String
rows = Split(tabAndCrLfDelimitedText, vbCrLf)
Dim r As Integer = 0
For Each line As String In rows
columns = Split(line, vbTab)
Dim c As Integer = 0
For Each cell As String In columns
values(r, c) = cell
c = c + 1
Next
r = r + 1
Next
Return values
End Function
The end result does what it needs to do and the function above is fairly reusable but I marked it Private as it is not general-purpose, and depends on the vbCrLf and vbTab delimiters.
This is clearly in the spirit of advice from #Mary ...
Thanks for the views and suggestions from stackoverflow folks!

validate strings in an excel in vb.net

I have a question, in vb.net, how can i validate that 2 values are the same in an excel in vb.net
for example i have defined 3 list
Public NSPS As New List(Of String)
Public CONTAINER As New List(Of String)
Public CONTAINER2 As New List(Of String)
I have 2 excel files where CONTAINER and CONTAINER2 are id's
So i need to create a third excel file that filters only the id's that repeat themselves in the 2 excel
meaning if i have an id: CARU9891569 in the 2 files, only then it transfers to the generated excel
and the 2 excel's have some extra information, for example: excel 1 has the variables: DELIVERY, CONTAINER, VOLUME.
the second excel has the variables: NSPS, NPOS, PACKAGES, CONTAINER2
SO the generated excel needs to have all of the variables: DELIVERY, CONTAINER, VOLUME, NSPS, NPOS, PACKAGES. using CONTAINER as the filter
to just fill information in a new excel i use this code
i use a function like this to extract the information from the excel files
Function extraer_valores_planilla(ByRef ruta As String) As Boolean
ExcelPackage.LicenseContext = LicenseContext.NonCommercial
Try
Dim stream = System.IO.File.OpenRead(ruta)
Dim package = New OfficeOpenXml.ExcelPackage(stream)
'// Libro
Dim Workbook = package.Workbook
'// Hojas
Dim hojas = Workbook.Worksheets
' While (Workbook.Worksheets.Count >= aux)
Dim hojaUsuarios = Workbook.Worksheets(Workbook.Worksheets.Item(0).ToString)
Dim indice As Integer = 2
While (indice < 5000)
'Numero entrega'
If (IsNothing(hojaUsuarios.Cells("A" & indice).Value) = False) Then
NSPS.Add(hojaUsuarios.Cells("A" & indice).Value)
End If
indice += 1
End While
indice += 1
Catch EX As Exception
MsgBox(EX.ToString)
Return False
End Try
Return True
and then i fill the third excel like this
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
ExcelPackage.LicenseContext = LicenseContext.NonCommercial
Dim path As String = seleccionardirectorio("Excel|.xlsx")
If (String.IsNullOrWhiteSpace(path) = False) Then
Dim excel = New ExcelPackage(New FileInfo(path))
excel.Workbook.Worksheets.Add("Hoja1")
Dim aux As Integer = 1
Dim Workbook = excel.Workbook
Dim hojas = Workbook.Worksheets
Dim dict As New Dictionary(Of String, String)
Dim hoja1 = Workbook.Worksheets("Hoja1")
'DAMOS NOMBRE A LAS COLUMNAS
INICIALIZAR_PLANILLA(hoja1)
While (aux <= CONTAINER.Count)
hoja1.Cells("C" & aux + 1).Value = ENTREGA.Item(aux - 1)
aux += 1
End While
this is the same for all variables i just resume for you guys and this works just fine.
should i use 2 cicles to filter the excel, maybe a for each, sorry i am new to programing and i am stuck in this part
any ideas would be helpfull
Thanks in advance!
yes, use 2 for each loops.
for each item in list
for each otheritem in list2
if item = otheritem then
' These items match
end if
next
next
Replace the dummy variables with yours

How to export comma delimited data to excel sheet, but each row is a new excel sheet

i have a comma delimited text file as follows
RLGAcct#,PAYMENT_AMOUNT,TRANSACTION_DATE,CONSUMER_NAME,CONSUMER_ADD_STREET,CONSUMER_ADD_CSZ,CONSUMER_PHONE,CONSUMER_EMAIL,LAST_FOUR
ZTEST01,50.00,11/15/2018,ROBERT R SMITH,12345 SOME STREET,60046,,adam#adamparks.com,2224
ZTEST02,100.00,11/15/2018,ROBERT JONES,5215 OLD ORCHARD RD,60077,,adam#adamparks.com,2223
ZTEST03,75.00,11/15/2018,JAMES B MCDONALD,4522 N CENTRAL PARK AVE APT 2,60625,,adam#adamparks.com,2222
ZTEST04,80.00,11/15/2018,JOHN Q DOE,919 W 33RD PL 2ND FL,60608,,adam#adamparks.com,2221
ZTEST05,60.00,11/15/2018,SAMANTHAN STEVENSON,123 MAIN ST,60610,,adam#adamparks.com,2220
I need to export this to excel so that each value between a comma is inserted into a column in excel
So
ZTEST01 is in A1,
50.00 is in B1
11/15/2018 in C1 ...
The thing is i need each row to be inserted into a newly created excel worksheet.
The code i have is as follows:
Dim xlApp As New Excel.Application
Dim xlWorkbook As Excel.Workbook
Dim xlWorksheet As Excel.Worksheet
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'xlWorkbook = xlApp.workboos.Add() using this later once i have the parsing figured out
Dim columns As New List(Of String)
Dim ccPayment = "C:\Users\XBorja.RESURGENCE\Downloads\Payments_Credit.txt"
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(ccPayment)
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim currentRow As String()
'Loop through all of the fields in the file.
'If any lines are corrupt, report an error and continue parsing.
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
' Include code here to handle the row.
For Each r In currentRow
columns.Add(r)
C
Next r
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
'Dim index0 = columns(0)
'Dim index1 = columns(1)
'Dim index2 = columns(3)
'Dim index3 = columns(3)
'Dim index4 = columns(4)
'Dim index5 = columns(5)
'Dim index6 = columns(6)
'Dim index7 = columns(7)
'Dim index8 = columns(8)
'Console.WriteLine(index0 & index1 & index2 & index3 & index4 & index5 & index6 & index7 & index8)
End Using
For Each r In columns
Console.WriteLine(r)
Next
end sub
As you can see I was trying to see if i could index these so that i could possibly equate each one to a cell in excel.
The other problem is that this text file changes daily. The columns are always set (9 columns) but the rows change dynamically daily based on how many transactions we get.
I would recommend using the EPPlus package which is available via NuGet. It removes the COM challenges of working with Excel and works by reading and writing the XLSX spreadsheet files.
The following sample does what you where asking:
Private Sub btnStackOverflowQuestion_Click(sender As Object, e As EventArgs) Handles btnStackOverflowQuestion.Click
Dim ccPayment As String = "C:\temp\so.csv"
Using pkg As New ExcelPackage()
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(ccPayment)
MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
MyReader.Delimiters = New String() {","}
Dim sheetCount As Integer
While Not MyReader.EndOfData
sheetCount += 1
Dim newSheet As ExcelWorksheet = pkg.Workbook.Worksheets.Add($"Sheet{sheetCount}")
Try
Dim currentRow As String() = MyReader.ReadFields()
Dim columnCount As Integer = 0
For Each r In currentRow
columnCount += 1
newSheet.Cells(1, columnCount).Value = r
Next r
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & " is invalid. Skipping")
End Try
End While
End Using
Dim fi As New FileInfo("C:\temp\so.xlsx")
pkg.SaveAs(fi)
End Using
End Sub

VB.NET (Excel Two Columns > Conditional Comboboxes)

I'm searching for nearly two hours to find a solution on the following. In Excel I have two columns (One Column for Master Records and one Column for Slave Records). Basically, in Combobox1 I want to populate all the Master Records. If a selection is made for MasterRecord A, I want Combobox2 to only show me the SlaveRecords belonging to A and not the other records belonging to other Master Records.
I have the Interop Assembly added and Excel opened (there is a connection already). Your help is much appreciated!
Private Sub Combobox2_Populate()
'Start Excel Script to populate ComboBox2
Dim excel As Application = New Application
Dim w As Workbook = excel.Workbooks.Open(Filename:=databasestatus, [ReadOnly]:=True)
Dim sheet As Worksheet = w.Sheets("AIR_NL_1")
Dim StartRow As Integer
Dim TotalRows As Integer
ComboBox2.Items.Clear()
sheet.UsedRange.AutoFilter(Field:=9, Criteria1:=ComboBox1.SelectedItem, Operator:=XlAutoFilterOperator.xlFilterValues)
TotalRows = sheet.Range("A1").CurrentRegion.Rows.Count
For StartRow = 3 To TotalRows
If XlCellType.xlCellTypeVisible = True Then
ComboBox2.Items.Add(sheet.Range("H:H").Cells(StartRow, 1).Text)
End If
Next
w.Close(SaveChanges:=False)
End Sub
This might help you, or at least give you a basic idea:
Private Function ExcelToDataTable(ByVal fileExcel As String, _
Optional ByVal columnToExtract As String = "*", _
) As System.Data.DataTable
Dim dt As New System.Data.DataTable
Try
Dim MyConnection As System.Data.OleDb.OleDbConnection
Dim MyCommand As OleDbDataAdapter
Dim fileExcelType As String
'Chose the right provider
If IO.Path.GetExtension(fileExcel.ToUpper) = ".XLS" Then
fileExcelType = "Excel 8.0"
MyConnection = _
New System.Data.OleDb.OleDbConnection _
("provider=Microsoft.Jet.OLEDB.4.0;Data Source='" & fileExcel & "';Extended Properties=" & fileExcelType & ";")
Else
fileExcelType = "Excel 12.0"
MyConnection = _
New System.Data.OleDb.OleDbConnection _
("provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & fileExcel & "';Extended Properties=" & fileExcelType & ";")
End If
'Open excel connection
MyConnection.Open()
'Populate DataTable
Dim myTableName = MyConnection.GetSchema("Tables").Rows(0)("TABLE_NAME")
MyCommand = New OleDbDataAdapter(String.Format("SELECT " & columnToExtract & " FROM [{0}] ", myTableName), MyConnection)
MyCommand.TableMappings.Add("Table", columnToExtract)
MyCommand.Fill(dt)
MyConnection.Close()
Catch ex As Exception
Err.Clear()
End Try
Return dt
End Function
As you can see, we have an optional parameter called myWhereStatement.
What does it mean?
You can specify its value when you call the function, otherwise its value will be an empty string
After that we can call ExcelToDataTable inside our Sub in order to populate the ComboBox as shown below:
Private Sub Combobox_Populate()
Dim filePath As String = "your_file_path"
ComboBox1.DataSource = ExcelToDataTable(filePath, "MasterRecord")
End Sub
Now you have your ComboBox1 filled with data, but the ComboBox2 is still empty.
We are going to handle the event of ComboBox1_SelectedValueChanged that means that every time you select an Item from the ComboBox1 it will programmatically fill the ComboBox2 with the propper items as shown below.
Private Sub ComboBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedValueChanged
Dim slaveRecords As System.Data.DataTable = ExcelToDataTable(filePath)
Dim dt As New DataTable
dt.Columns.Add("SlaveRecords")
For i As Integer = 0 To slaveRecords.Rows.Count
If ComboBox1.SelectedItem Is slaveRecords.Rows(i).Item(0) Then
dt.Rows.Add(slaveRecords.Rows(i).Item(1))
End If
Next
ComboBox2.DataSource = dt
End Sub
Remarks
As you can see the first call of ExcelToDataTable has only 2 parameters while the second one has 3 parameters. That's the optional parameter feature!
N.B.
As you can see I'm using alot of _ because of better code formatting. It means that a single statement will continue across multiple lines
If something isn't 100% clear ot you have any dubt feel free to ask in the comments below.

VB.Net Working with and Manipulating an Excel Spreadsheet

I want to iterate through a row in my dataset. If the first cell of the row is of the pattern 1234-Name, then I want to strip the number (1234) from that and save it as a variable. Basically, the first cell is the employee and their number, like 1234-Bob McDonald. If it isn't of that form then I want to ignore it and move to the next row.
Then I want to go cell by cell in the same row, and whatever is in the cell, save it to a different variable (column 2 is location, column 3 is number of hours worked, etc.)
Here is the code I have so far:
Public Function ReadXLFile(ByVal FileName As String) As DataSet
Dim MyConnection As System.Data.OleDb.OleDbConnection
Dim Ds As System.Data.DataSet
Dim MyAdapter As System.Data.OleDb.OleDbDataAdapter
MyConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FileName & "Extended Properties=Excel 16.0;")
MyAdapter = New System.Data.OleDb.OleDbDataAdapter("Select * from [Sheet1$]", MyConnection)
Ds = New System.Data.DataSet
MyAdapter.Fill(Ds)
Return Ds
End Function
How about this?
Public Sub GetData(ByVal FileName As String)
Dim strEmployeeNumber As String
Dim strEmployeeName As String
Dim strLocation As String
Dim intHours As Integer
Dim myDataSet As DataSet = ReadXLFile(FileName)
Dim myFirstCell As String
Dim mMatch As Match
Dim r As Regex = New Regex("^[0-9]+-[A-Za-z]+")
Dim arrFirstCell() As String
For Each myDr As DataRow In myDataSet.Tables(0).Rows
myFirstCell = myDr.Item(myDataSet.Tables(0).Columns(0))
mMatch = r.Match(myFirstCell)
If mMatch.Success Then
arrFirstCell = Split(mMatch.Value, "-")
strEmployeeNumber = arrFirstCell(0)
strEmployeeName = arrFirstCell(1)
strLocation = myDr.Item(myDataSet.Tables(0).Columns(1))
intHours = CInt(myDr.Item(myDataSet.Tables(0).Columns(2)))
Console.WriteLine("Number: {0} Name: {1} Location: {2} Hours: {3}", strEmployeeNumber, strEmployeeName, strLocation, intHours)
End If
Next
End Sub

Resources