Datatables left join linq - vb.net

I'm having a hard time joining 2 datatables and have the joined datatable
as result.
First datatable (labels) holds data including a printerid.
Second datatable (printers) holds printer references (id > unc)
I would like to have as endresult (joined) a datatable with all data
from the first datatable with the field (unc) of the second datatable.
This is what i have been trying: (mind that fixed paths are for convenience...)
Sub Main()
Dim ds1 As new DataSet
ds1.ReadXml("C:\Program Files (x86)\[COMPANY]\ASW2XML\BICOLOR_a07bfc62-501e-4444-9b6e-3b9d3550e1a4.xml")
Dim ds2 As New DataSet
Dim li As string()
li = IO.File.ReadAllLines("C:\Program Files (x86)\[COMPANY]\ASW2XML\printers.dat")
Dim printers As New DataTable("Printers")
printers.Columns.Add("REPRT2")
printers.Columns.Add("REPRT3")
For Each s In li.ToList
Dim dr As DataRow = printers.NewRow
dr.Item(0) = s.Split("=")(0)
dr.Item(1) = s.Split("=")(1)
printers.Rows.Add(dr)
Next
printers.AcceptChanges
Dim labels As DataTable = ds1.Tables(0)
Dim joined As new DataTable("data")
'Dim lnq = From label In labels.AsEnumerable Join printer In printers.AsEnumerable On label("REPRT") Equals printer("REPRT2") Select printer
'Dim lnq = From l In labels Group Join p In printers On l Equals p("REPRT2") Into Group From p In Group Select label = l, ppath = If(p Is Nothing, "(Nothing)", p("REPRT3"))
Dim lnq = labels.AsEnumerable().Where(Function(o)printers.Select("REPRT2 =" & o.Item("REPRT").ToString).Length = 0)
joined = lnq.CopyToDataTable
End Sub
Thx for your help and inspiration!
grtz -S-

Have you tried http://msdn.microsoft.com/en-us/library/system.linq.enumerable.join.aspx
Make your datatables as an extension of IEnumerable (like list as you did) and a join in linq would make it work easily.
then send the joined tables to any destination you want.

I thought a comment would be harder to understand so I moved it in a post.
I wrote a bit of strucure that shoud help you understand how Join works:
structure Label
Public printerId as long
Public driver as Strring
end structure
structure Printer
Public unc as string
end structure
If you set Labels and Printers to DataTable (instead of the structures below), you shoud have something like :
function DoJoin() as datatable
'You might remove as datatable in query declaration
dim query as datatable = Labels.Join(Printers, Function(aLabel) aLabel, _
function(aPrinter) aPrinter.unc, _
function(aLabel, aPrinter) New With
{ .printerID = aLabel.printerId, .driver = aLabel.Driver, _
.unc = aPrinter.unc
})
return query
end function
However I wote it this morning in notepad, so you might have to adjust this. I just want to add that you must have the same type of container in order to use join (eg : example in Join at msdn they used 2 Lists.), that are compatible with Linq obects (datatable I do not know).

I decided to do it the "hard" way and loop through all rows in parent table.
This goes very fast for a minor amount of records, I don't know if running this on
a larger amount of records speed will greatly decrease over using a Linq solution...
This is the code that I'm using atm:
Sub Main()
Dim ds As new DataSet
ds.ReadXml("C:\Program Files (x86)\[COMPANY]\ASW2XML\BICOLOR_a07bfc62-501e-4444-9b6e-3b9d3550e1a4.xml")
Dim labels As DataTable = ds.Tables(0)
Dim printers As DataTable = GetPrinters
labels.Columns.Add("REPRT2").SetOrdinal(labels.Columns.IndexOf("REPRT")+1) 'insert new column after key column
labels.CaseSensitive=False
labels.AcceptChanges
For Each dr As DataRow In labels.Rows
Dim p As String = String.Empty
Try
p = printers.Select("ID='" & dr("REPRT") & "'")(0).Item("PATH").ToString
Catch ex As Exception
End Try
dr("REPRT2") = p
Next
labels.AcceptChanges
End Sub
Function GetPrinters As DataTable
Dim printers As New DataTable("Printers")
Dim li As string()
li = IO.File.ReadAllLines("C:\Program Files (x86)\[COMPANY]\ASW2XML\printers.dat")
printers.Columns.Add("ID")
printers.Columns.Add("PATH")
For Each s In li.ToList
Dim dr As DataRow = printers.NewRow
dr.Item(0) = s.Split("=")(0)
dr.Item(1) = s.Split("=")(1)
printers.Rows.Add(dr)
Next
printers.AcceptChanges
Return printers
End Function

Related

Parsing through DataTable for matching value and creating a new DataTable from the results

In VB.NET I'm trying to count through the value's in a list, until the value for "stock" in my DataTable, Boxes, is equal to the value in my list. When this occurs a row should be created in my new DataTable "output". I would then continue counting through the list looking for other matching instances to add into "output".
So far counting through the list and then within that count going through the datatable to match value's works wonderfully. The part where I'm getting hung up is when I try to take the matching row and put it into another table.
Dim output As DataTable
Dim jsonstringy As String = BoxComms.WebGet("http://foo.foo.foo") 'PULLS JSON STRING
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim MyString As String = TextBox1.Text 'MAKE STRING OF STOCK #'s FROM TEXTBOX
MyString = MyString.Replace(" ", "") 'GET RID OF SPACES
Dim MyArray() As String = MyString.Split(",") 'SEPERATE COMMA DELIMETED LIST
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList 'COUNT THROUGH LIST OF STOCK #'s
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then 'IF STOCK # IS EQUAL TO ANY OF NUMBERS IN TEXTBOX
output.ImportRow(row) 'ADD ROW FROM DATATABLE Boxes to DATATABLE output
End If
Next row
Next
The solution was fairly simple, my DataTable needed a schema first. in order to copy the schema all I needed was to initialize the new table as a clone. to do so the code was as follows.
Dim output As DataTable = Boxes.Clone()
clone vs copy. copy get's the schema and data clone just gets the schema. then as I was parsing through the first table looking for matches I had to add the row to my new table with the following code.
output.Rows.Add(row.ItemArray)
the full code is as follows
Dim jsonstring As String = BoxComms.WebGet("https://foo.foo.foo")
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim output As DataTable = Boxes.Clone()
Dim MyString As String = TextBox1.Text
MyString = MyString.Replace(" ", "")
Dim MyArray() As String = MyString.Split(",")
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then
Console.WriteLine(row("stock"))
output.Rows.Add(row.ItemArray)
End If
Next row
Next
BoxControl.DataGridView1.DataSource = output
Me.Close()
End If

Can you populate a Dataset with User Input?

I need to store user input (entered from the console) to a Dataset in Visual Basic. Is this possible? I can't seem to find any information online about doing so. If anyone can point me in the right direction, that would be awesome!
EDIT: The columns in my table are FirstName, LastName, State, etc. in a table named Person.
The start of the application for the console: "Enter FirstName: ", then "EnterLastName: " then etc.
The values for the user inputs are stored in there specific variables eg. firstName, lastName, so I want to know how I can put those variables in a dataset.
Thank you.
Here is a short and basic example. Most likely it will not directly work for what you need as you will probably want to use a typed dataset among other things. Since your question does not specify a question regarding the code you may have already tried, this all I am going to provide.
Option Strict On
Module Module1
Sub Main()
Dim ds As DataSet = CreateNewDataSet()
Dim entries As New List(Of String())
For i = 1 To 3
Console.WriteLine($"Enter first column value for row {i.ToString}:")
Dim input1 As String = Console.ReadLine()
Console.WriteLine($"Enter second column value for row {i.ToString}:")
Dim input2 As String = Console.ReadLine()
entries.Add({input1, input2})
Next
entries.ForEach(Sub(x) ds.Tables(0).Rows.Add(x))
End Sub
Private Function CreateNewDataSet() As DataSet
Dim ds As New DataSet()
Dim dt As New DataTable()
Dim col1 As New DataColumn("Column1")
Dim col2 As New DataColumn("Column2")
dt.Columns.AddRange({col1, col2})
ds.Tables.Add(dt)
Return ds
End Function
End Module
If you don't know column names, you can use reflection to get names of properties of input objects. You can also use attributes to filter properties. Use DataTable.LoadDataRow method to load an array as row.
here is an example to how to do it dynamically:
Dim input As New List(Of Object)
For i = 0 To 5
Console.WriteLine("enter your first name and last name:")
input.Add(New With {.First = Console.ReadLine, .Last = Console.ReadLine})
Next
Dim myData As New DataSet
Dim table = myData.Tables.Add()
table.Columns.AddRange(input.First.GetType.GetProperties.Select(Function(p) New DataColumn(p.Name)).ToArray)
input.ForEach(Function(o) table.LoadDataRow(o.GetType.GetProperties.Select(Function(p) p.GetValue(o, Nothing)).ToArray, False))
For Each row In table.Rows
Console.WriteLine("first:{0} ,Last:{1}", row(0), row(1))
Next

how to increase datatable's name number in vb.net

I know, how to increase integer, string by for statement
but I want know how to change the name by 'for ~next' statement.
For example,
Dim row_sort1 As DataTable = rows1.CopyToDataTable
Dim row_sort2 As DataTable = rows2.CopyToDataTable
Dim row_sort3 As DataTable = rows3.CopyToDataTable
Dim row_sort4 As DataTable = rows4.CopyToDataTable
Dim row_sort5 As DataTable = rows5.CopyToDataTable
Dim row_sort6 As DataTable = rows6.CopyToDataTable
Dim row_sort7 As DataTable = rows7.CopyToDataTable
I had coding like this,, bad cording So I want change by 'for ~next' statement.
I want increase the datatable name's number (1~7)
how can reflect in this coding. I want fix my coding more simple and useful.
I need your help
thank you
I assume you have a Collection of Rows which is your master where you want to copy from.
I have a similiar approach like OSKM. Better use a list collection than an array.
To access tables afterwards in the collection you can use Linq.
' Given master rowcollection
Dim masterRow As EnumerableRowCollection(Of DataRow)
' Empty table collection
Dim tableList As New List(Of DataTable)
For t As Integer = 0 To 6
' copy Master to a new table
Dim newTable As DataTable = masterRow.CopyToDataTable()
' give the new table a name
newTable.TableName = "Table" & t.ToString
' Add new table to collection
tableList.Add(newTable)
Next
' Access a certain table (i.e. Table5) using Linq
Dim table5 As DataTable = tableList.FirstOrDefault(Function(x) x.TableName = "Table5")
If i understand your question correct the following might help.
'Note your datatables will be named Datatable0 to Datatable6
Dim DTs(6) As DataTable
For i = 0 To 6
DTs(i) = New DataTable
DTs(i).TableName = "Datatable" & i
Next
There is probably better ways but this will work!

How to import csv file in Datagridview with certain columns and rows?

I'm new to VB.net and I don't know how to display certain columns and rows in datagridview that was imported from CSV file. My problem is I have many columns and all I want to display is 2 columns:
Name,Age,Mobile Number,ID number
Alex,18,09848484841,0010
George,19,02987654321,0020
Toni,17,09277470257,0030
How can I display only the Name & Age columns and its rows?
If you use a datatable you get the data structure and collection together. something like this:
Dim sr As New IO.StreamReader(filename)
Dim dt As New DataTable
Dim newline() As String = sr.ReadLine.Split(","c)
dt.Columns.AddRange({New DataColumn(newline(0)), _
New DataColumn(newline(1))})
While (Not sr.EndOfStream)
newline = sr.ReadLine.Split(","c)
Dim newrow As DataRow = dt.NewRow
newrow.ItemArray = {newline(0), newline(1)}
dt.Rows.Add(newrow)
End While
DataGridView1.DataSource = dt
Use a custom class with properties that match the data you want to store and make an instance of that class for each row of data use read, then have a List(Of {custom class}) to hold each object and the DGV's DataSource property can view the collection in the grid. The property names in the class will be used as the header.

Display all contents of a "table" created in LINQ in VB.NET

Working from a previous question I asked (which was answered very well).. Ive come across another snag... In the following code
Public Sub Main()
Dim EntireFile As String
Dim oRead As System.IO.StreamReader
oRead = File.OpenText("testschedule.txt")
EntireFile = oRead.ReadToEnd
Dim table As New List(Of List(Of String))
' Process the file
For Each line As String In EntireFile.Split(Environment.NewLine)
Dim row As New List(Of String)
For Each value In line.Split(",")
row.Add(value)
Next
table.Add(row)
Next
' Display all contents of 5th column in the "table" using LINQ
Dim v = From c In table Where c(5) = ""
For Each x As List(Of String) In v
Console.WriteLine(x(0)) ' printing the 1st column only
Next
Console.WriteLine("Value of (2, 3): " + table(1)(2))
End Sub
`
The area where it says Dim v = From c In table Where c(5) = "" the blank quotations will only accept a specific number that its looking for in that column.
For Example:
Dim v = From c In table Where c(5) = "7" Will only show me any 7's in that column. Normally there will be many different values and I want it to print everything in that column, I just cant figure out the command to have it display everything in the selected column
Once again Many MANY Thanks!
If you want to show all rows (to be precise: items in the IEnumerable), just remove the Where condition
Dim v = From c In table
Just a note: table is not a very good name for your list, it leads the thought to SQL. This is just Linq2Objects and you don't query tables you query plain objects with a syntax very similar to Linq2SQL that in turn is heavily inspired by SQL.