Selecting specific columns while writing it to CSV file - vb.net

I am writing a CSV file using a dataset. I need to only select few columns from my dataset not all the columns.
I am using below code but it's writing all the columns in the data row to CSV file.
I need to write only first, third and fifth columns to the CSV file and ignore second and fourth columns.
For Each row As DataRow In dsRefs.Tables(0).Rows
For i As Integer = 0 To dsRefs.Tables(0).Columns.Count() -
csvWriter.NextRecord()
Next
Next

A technique to resolve this might be;
Dim listOfColums = (From dtR As DataRow In dsRefs.Tables(0).Rows
Select r1 = dtR.Item(0), 'first
r2 = dtR.Item(2), 'third
r3 = dtR.Item(4)) 'fifth
Using sWriter As StreamWriter = New StreamWriter("C:\YouurPathToSaveCsv\YourFileCsv.csv")
Dim divider As String = ";"
If listOfColums IsNot Nothing AndAlso listOfColums.Count > 0 Then
For Each okList In listOfColums
Dim cRow As String = Strings.Join({okList.r1, okList.r2, okList.r3}, divider)
Console.WriteLine(cRow)
sWriter.WriteLine(cRow)
Next
End If
End Using

Related

Why does my stacked column chart print incorrect x axis labels?

A bit of information:
I would like to populate a stacked column chart with transactions from the last 12 months.
Every column should be a month in the year and the transactions are of course stacked on top of each other.
At the moment, I just have a test document where I pull some data from. I first tried to directly put the data (from the csv) in the chart, but that just resulted in multiple columns with the multiple duplicate x axis label and nothing stacked.
I did some digging and found this solution. unfortunately, the result is not what I'm looking for. The transactions are stacked but the x axis labels are incorrect
At the moment I have
Dim rowsTra() As String = File.ReadAllLines(".\data\transactions.csv")
Dim traVal() As String
Dim preYear As DateTime = DateTime.Now.AddYears(-1)
Dim j As Integer = 0
Dim dtTest As DataTable = New DataTable
dtTest.Columns.Add("col1", GetType(Double))
dtTest.Columns.Add("col2", GetType(String))
dtTest.Columns.Add("col3", GetType(String))
For i As Integer = 0 To rowsTra.Length - 1 Step +1 ' Looping through all transactions
traVal = rowsTra(j).ToString().Split(",")
Dim traDate As String = Convert.ToDateTime(traVal(1))
If (traDate >= preYear) Then ' Check if date is not older than 1 year
Dim conMonth As Date = CDate(traVal(1))
Dim month = conMonth.ToString("MMM yyyy")
dtTest.Rows.Add(traVal(6), month, traVal(4))
Else
i = rowsTra.Length - 1 ' Quit loop if year ends (will only work if csv is chronological
End If
j += 1
Next
Dim dv As DataView = New DataView(dtTest)
dv.Sort = "col2 asc"
chTrend.Series.Clear()
chTrend.Titles.Clear() ' Clear
chTrend.DataBindCrossTable(dv, "col3", "col2", "col1", "Label=col1") ' Populate chart
For Each cs As Series In chTrend.Series ' Stack values
cs.ChartType = SeriesChartType.StackedColumn
Next
By using this csv file I get this result:
Account 1,19 Dec 2021,Man 1,Cat 1,Subcat 1,test,5
Account 2,01 Dec 2021,Man 2,Cat 2,Subcat 2,test,10
Account 5,01 Nov 2021,Man 4,Cat 2,Subcat 2,test,10
Account 4,27 Oct 2021,Man 4,Cat 4,Subcat 4,test,20
Account 3,10 Oct 2021,Man 3,Cat 3,Subcat 3,test,15
Account 1,03 Sep 2020,Man 1,Cat 1,Subcat 1,test,25
= col2 =col3 =col1
Why would it in this case add 4 transactions under the "Dec 2021" when only 2 transactions actually are?
I've noticed that when I change the 3rd listed transaction to another Subcat, all transactions fall under Dec 2021.
Ive also tried to just give col2 in dtTest the Date type but this just gave an even weirder chart and I'm not sure how to then format the date to "MMM yyyy". This is my reason to move from datetime to string
I'm not sure what I'm doing wrong.
Thanks for the input. Sorry for the messy code, still learning.
So I did some experimenting myself and I believe I found "A" solution to my problem.
I'm sharing it, since it might be to helpful to someone in the future.
In the end I came up with this solution.
It not only stacks correctly by adding the extra rows needed (as mentioned in my comment), but also adds up values from already existing categories.
This is something that I was aiming for did not mention in my original question.
I'm definitely not saying this is the best solution and I know it can cause some performance issues with scalability. I'd go so far as to say it might even be just spaghetti code so I'd love to see someone with more experience find a more optimal solution to this problem.
Dim rowsTra() As String = File.ReadAllLines(".\transactions.csv")
Dim traVal() As String
Dim strCat As String = ""
Dim strDate As String = ""
Dim preYear As DateTime = DateTime.Now.AddYears(-1) ' Start date for all visible transactions in chart
Dim dtTrend As DataTable = New DataTable
dtTrend.Columns.Add("outflow", GetType(Double)) ' Columns for DataTable
dtTrend.Columns.Add("date", GetType(String))
dtTrend.Columns.Add("category", GetType(String))
Dim valExist As Boolean
Dim l As Integer = 0 'l
Dim m As Integer = 0 'm
For i As Integer = 0 To rowsTra.Length - 1 Step +1 ' Loop all transactions to add to DataTable and list all dates and categories
traVal = rowsTra(l).ToString().Split(",")
Dim traDate As String = Convert.ToDateTime(traVal(1))
Dim traMonth = CDate(traVal(1)).ToString("MMM yyyy") ' Convert to Month Year
If (traDate >= preYear) Then ' Check if date is not older than 1 year
If dtTrend.Rows.Count = 0 Then ' First transaction loop
dtTrend.Rows.Add(traVal(6), traMonth, traVal(4)) ' Add row to DataTable in order "outflow/date/category"
Else ' If not first transaction
m = 0
valExist = False ' Reset valExist to false
While m < dtTrend.Rows.Count ' Loop DataTable, used to add outflow to existing categories
If dtTrend.Rows(m)(1).ToString = traMonth And dtTrend.Rows(m)(2) = traVal(4) Then ' Check if date and category match between DataTable and Transactions
dtTrend.Rows(m)(0) = dtTrend.Rows(m)(0) + traVal(6) ' Add outflow to existing DataTable row
m = dtTrend.Rows.Count
valExist = True
End If
m += 1
End While
If valExist = False Then ' If combo of date and subcategory does not exist:
dtTrend.Rows.Add(traVal(6), traMonth, traVal(4)) ' Add new line to DataTable
End If
End If
If strCat = "" Then ' If string has no value (first loop). Used to create list of subcategories
strCat = traVal(4)
ElseIf strCat.Contains(traVal(4)) Then ' Check if category already exist in the string
Else
strCat = strCat + "," + traVal(4)
End If
If strDate = "" Then ' Ditto about but for Date
strDate = traMonth
ElseIf strDate.Contains(traMonth) Then
Else
strDate = strDate + "," + traMonth
End If
Else
i = rowsTra.Length - 1 ' Quit loop if year ends (will only work if csv is chronological
End If
l += 1
Next
Dim arrCat() As String = strCat.Split(",") ' Split string to use in array
Dim arrDate() As String = strDate.Split(",")
Dim tfMatch As Boolean
For i As Integer = 0 To arrCat.Length - 1 Step +1 ' Loop existing categories, used to add non existing row
For j As Integer = 0 To arrDate.Length - 1 Step +1 ' Loop existing dates, rows need to be added to get full series
Dim dtRows = dtTrend.Rows.Count
For k As Integer = 0 To dtRows - 1 ' Loop through original DataTable values
If dtTrend.Rows(k)(1) = arrDate(j) And dtTrend.Rows(k)(2) = arrCat(i) Then ' Check if date and categorys match anywhere in the DataTable
tfMatch = True
End If
Next
If tfMatch = True Then ' If match, reset and search with next date
tfMatch = False
Else
dtTrend.Rows.Add(0, arrDate(j), arrCat(i)) ' If no match, add as new row in DataTable
tfMatch = False ' Reset, moving to next category
End If
Next
Next
Dim dv As DataView = New DataView(dtTrend)
dv.Sort = "date desc"
chTrend.Series.Clear() ' Clear chart before fill so no exceptions are generated
chTrend.Titles.Clear()
chTrend.DataManipulator.FilterSetEmptyPoints = True ' Filter to get correct stack
chTrend.DataManipulator.FilterMatchedPoints = True
chTrend.DataBindCrossTable(dv, "category", "date", "outflow", "Label=outflow") ' Populate chart
For Each cs As Series In chTrend.Series ' Removes labels of newly added rows with value "0"
chTrend.DataManipulator.Filter(DataVisualization.Charting.CompareMethod.EqualTo, 0, cs) 'Compare if equal to zero, filter out
cs.ChartType = SeriesChartType.StackedColumn ' Chart type
'Dim dpcp As DataPointCustomProperties = New DataPointCustomProperties
Next

VB.net deleting row from DT

I have the below code which works fine, although I want it to only delete the row if the whole row is empty. At the moment if there is no text in the first column it deletes the row even though there maybe text in the other columns.
Also want to trim the text as sometimes there are spaces in the columns with no text. this will ensure that blank rows are deleted.
Any help is greatly appreciated.
Thanks
For i As Integer = dt.Rows.Count - 1 To 0 Step -1
Dim row As DataRow = dt.Rows(i)
If row.Item(0) Is Nothing Then
dt.Rows.Remove(row)
ElseIf row.Item(0).ToString.Trim = "" Then
dt.Rows.Remove(row)
End If
Next
You are deleting the rows from just a datatable not from database.
Below code could help you.
Dim valuesarr As String = String.Empty
For i As Integer = 0 To dt.Rows.Count - 1
Dim lst As New List(Of Object)(dt.Rows(i).ItemArray)
For Each s As Object In lst
valuesarr &= s.ToString 'can use trim here if you want to delete spaces
Next
If String.IsNullOrEmpty(valuesarr) Then
'Remove row here, this row do not have any value
dt.Rows(i).Remove()
End If
Next

System.InvalidCastException Error on Specific Database Column

So I am currently trying to read values from an access database and write them to an array of labels in VB.NET. This is for a little quiz program I am making where the previous scores they got in the 14 categories are written to the screen. The issue I am having is when writing to Label7 (column 20 in the database) I get the error 'specified cast is not valid'. I have checked my txt file and database thoroughly to see what is wrong with this specific value and I cannot see a difference. It is still written as a 32 bit integer like all the others, for which the code has no issues.
Dim LabelArray() As Control = {Label1, Label2, Label3, Label4, Label5, Label6, Label7, Label8, Label9, Label10, Label11, Label12, Label13, Label14}
Dim x As Integer = 2
'starting at the the 3rd column in the database
Dim QArray(13) As String 'reading names of the columns from a txt file into the array
FileOpen(1, Application.StartupPath & "\sqlscores.txt", OpenMode.Input) 'load files
Dim j As Integer = 0
Do While Not EOF(1)
QArray(j) = LineInput(1) 'input into array
j = j + 1
Loop
FileClose(1)
Dim tbl As New DataTable
Dim conn1 = MyConnection2() 'connects to microsoft access database
Dim temp As String
For i = 0 To 13 'for each item in the array
Dim command = New OleDbCommand("Select * From Users Where Username='" & usernames & "' and " & QArray(i) & " >= 0", conn) 'look for that column in the database where their username and score is more than 0
Dim reader = command.ExecuteReader()
While reader.Read()
temp = (reader.GetInt32(x)).ToString 'read value and convert to string
LabelArray(i).Text = temp 'assign temp to label text
x = x + 3 'increment by 3 as correct column is in every third column
End While
Next i
Below is a screenshot of the database (the specific column) that is causing the issue.
The first field is the section that is playing up
As you can see, it has the same properties as a section that does work compared to a section that does
I have tried deleting the column and adding it again, which makes no difference. I have also checked the label (and re-added it) in VB to see if that was the issue, which it was not. It appears to think that the value in that column, which is just currently the 32 bit integer "4" cannot be converted to a string. I am only interested in the practice scores in the db which can be seen in the column names.
Am I missing something obvious?

First row as header in datagridview

Imported data from CSV to datagridview has header in first row, I could hide that row and name header for every column, problem is that data table has 68 columns. Is it possible to make first row header without having to do that manually for every single column?
Your datagrid should have taken all column names from CSV, if not then you need to have a look at this great article. It will help you a lot. This is the link.
After experimenting and help from user: ooopsoft :
Dim TextFieldParser1 As New Microsoft.VisualBasic.FileIO.TextFieldParser(receiveStream)
TextFieldParser1.Delimiters = New String() {","}
Dim newline() As String = TextFieldParser1.ReadFields()
While Not TextFieldParser1.EndOfData
Dim Row1 As String() = TextFieldParser1.ReadFields()
If DataGridView1.Columns.Count = 0 AndAlso Row1.Count > 0 Then
Dim i As Integer
For i = 0 To Row1.Count - 1
DataGridView1.Columns.Add(newline(i), newline(i))
Next
End If
End While

Adding two column values to listbox in vb.net

I have a table named users which has the following columns in it
User_id,user_name,user_pwd,First_Name,Middle_Name,Last_Name and user_type.
I have dataset named dst and created a table called user in the dataset. Now I want to populate listbox with user_Name, First_Name, Last_name of each and every row in the table user.
I am able to add one column value at a time but not getting how to add multiple column values of each row to listbox
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(row("User_Name"))
Next
Above code works perfectly but I also want to add First_name as well as last_name to the list box at the same time.
Use same approach as you have, but put all values you want in one string.
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
Dim sItemTemp as String
sItemTemp = String.Format("{0},{1},{2}", row("User_Name"), row("First_Name"), row("Last_Name"))
lstUsers.Items.Add(sItemTemp)
Next
String.Format() function will call .ToString() on all parameters.
In this case if row(ColumnName) is NULL value then .ToString() return just empty string
You have 2 choices:
Using the ListBox:
To use the ListBox, set the font to one that is fixed width like courier new (so that the columns line up), and add the items like this:
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(RPAD(row("User_Name"),16) & RPAD(row("First_Name"),16) & RPAD(row("Last_Name"),16))
Next
The RPAD function is defined like this:
Function RPAD(a As Object, LENGTH As Object) As String
Dim X As Object
X = Len(a)
If (X >= LENGTH) Then
RPAD = a : Exit Function
End If
RPAD = a & Space(LENGTH - X)
End Function
Adjust the LENGTH argument as desired in your case. Add one more for at least one space. This solution is less than ideal because you have to hard-code the column widths.
Use a DataGridView control instead of a ListBox. This is really the best option, and if you need, you can even have it behave like a ListBox by setting the option to select the full row and setting CellBorderStyle to SingleHorizontal. Define the columns in the designer, but no need to set the widths - the columns can auto-size, and I set that option in the code below. if you still prefer to set the widths, comment out the AutoSizeColumnsMode line.
The code to set up the grid and add the rows goes like this:
g.Rows.Clear() ' some of the below options are also cleared, so we set them again
g.AutoSizeColumnsMode = DataGridViewAutoSizeColumnMode.AllCells
g.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal
g.SelectionMode = DataGridViewSelectionMode.FullRowSelect
g.AllowUserToAddRows = False
g.AllowUserToDeleteRows = False
g.AllowUserToOrderColumns = True
For Each row As DataRow In dt.Rows
g.Rows.Add(row("User_Name"), row("First_Name"), row("Last_Name"))
Next
You might solved your problem by now but other users like me might have issue with it.
Above answers given worked for me even but I found a same answer in a simple way according to what I want..
cmd = New SqlCommand("select User_Name, First_Name, Last_Name from User")
Dim dr As SqlDataReader = cmd.ExecuteReader(YourConnectionString)
If dr.HasRows Then
Do While dr.Read
lst.Items.Add(dr.Item(0).ToString & " " & dr.Item(1).ToString & " " & dr.Item(2).ToString)
Loop
End If
This worked for me, maybe wrong way but I found it simple :)
May I suggest you use a ListView control instead of Listbox?
If you make the switch, here's a sample subroutine you could use to fill it up with the data you said you want. Adapt it the way you like; there's much room for improvement but you get the general idea:
Public Sub FillUserListView(lstUsers As ListView, Dst As DataSet)
Dim columnsWanted As List(Of String) = New List(Of String)({"User_Name", "First_Name", "Last_Name"})
Dim dt As DataTable = Dst.Tables("user")
Dim columns As Integer = 0
Dim totalColumns = 0
Dim rows As Integer = dt.Rows.Count
'Set the column titles
For Each column As DataColumn In dt.Columns
If columnsWanted.Contains(column.ColumnName) Then
lstUsers.Columns.Add(column.ColumnName)
columns = columns + 1
End If
totalColumns = totalColumns + 1
Next
Dim rowObjects(columns - 1) As ListViewItem
Dim actualColumn As Integer = 0
'Load up the rows of actual data into the ListView
For row = 0 To rows - 1
For column = 0 To totalColumns - 1
If columnsWanted.Contains(dt.Columns(column).ColumnName) Then
If actualColumn = 0 Then
rowObjects(row) = New ListViewItem()
rowObjects(row).SubItems(actualColumn).Text = dt.Rows(row).Item(actualColumn)
Else
rowObjects(row).SubItems.Add(dt.Rows(row).Item(actualColumn))
End If
lstUsers.Columns.Item(actualColumn).Width = -2 'Set auto-width
actualColumn = actualColumn + 1
End If
Next
lstUsers.Items.Add(rowObjects(row))
Next
lstUsers.View = View.Details 'Causes each item to appear on a separate line arranged in columns
End Sub