VB.Net DataTable.Select - Sort expression syntax - vb.net

I need to select rows from a DataTable and sort them by "Field1 / Field2"
I tried this code:
Using DT_Tmp As DataTable = DT.Select("", "FirstNum/SecondNum desc").CopyToDataTable
but I get error saying that column "FirstNum/SecondNum" doesn't exist.
EDIT
So far I'm using (as a workaround) a temp table which I'm adding a Field where I store the ratio and I'm using that Field to sort the table.

I don't think the select method is smart enough to do calculations on the field. The other workaround is to add a computed column to your datatable and use that as the sort column

Try putting each column inside brackets
Using DT_Tmp As DataTable = DT.Select("", "[FirstNum] / [SecondNum] desc").CopyToDataTable

Based on the links you looked at, you need to add the caluculated column first.
csortnum= New DataColumn
With csortnum
.DataType = System.Type.GetType("System.Decimal")
.ColumnName = "sortcolumn"
.Expression = "FirstNum/SecondNum"
End With
DT.add(csortnum)
Using DT_Tmp As DataTable = DT.Select("", csortnum desc").CopyToDataTable

Related

LINQ Order DataTable based on string date

I have a dataTable with column "date" which has dates in string format.
I can't sort it with LINQ.
Table example
ID date
1 20.02.2022
2 15.05.2021
3 03.07.2019
This is the LINQ expression I have so far, but it always says String was not recognized as a valid DateTime
(From x In dt.AsEnumerable()
Order By Convert.ToDateTime(x("date").ToString)
Select x).CopyToDataTable
I've also tried this, but with the same result
(From x In dt.AsEnumerable()
Order By DateTime.ParseExact(x("date").ToString,"dd/MM/yyyy",System.Globalization.CultureInfo.InvariantCulture)
Select x).CopyToDataTable
What am I missing ?
Make your life easy; use a strongly typed datatable. It can still be used like a normal datatable but it's less of a pig to work with
add a new DataSet type of file to your project
call it eg MyProjectNameHereDataSet
right click the design surface, choose Add DataTable, give it a nice name like Concerts
right click the DataTable and Add Column
call it ID, make it an int
add another column, call it something more interesting than Date - ConcertDate perhaps. Avoid naming columns words that are keywords or types
make it a DateTime type
This visual designer effectively just wrote you a class with two properties, int Id and DateTime ConcertDate, and it made a datatable capable of holding them.
When you're loading your data into your table, do the parsing then (you'll have to now it's strongly typed). It is more efficient to do so than doing it every time you query
Dim dt = new ConcertsDataTable()
'in a loop? Some api call? Wherever the data comes from
dt.AddConcertsRow(theId, DateTime.ParseExact(theDate, "dd.MM.yyyy", CultureInfo.InvariantCulture)
Now you can LINQ it more nicely; no need for AsEnumerabke, or digging column names out by string and casting them etc
dt.OrderBy(Function(r) r.ConcertDate)
Nice:
Dim totalAttendancePast = 0
For Each ro in dt
If ro.ConcertDate < DateTime.Now Then totalAttendancePast += ro.Attendance
Next ro
Nasty:
For Each ro as DataRow in dt.Rows
If DateTime.ParseExact(ro("ConcertDate"), "dd.MM.yyyy") < DateTime.Now Then totalAttendancePast += DirectCast(ro("Attendance"), Integer)
Next ro
Nicer:
dt.
Where(Function(r) r.ConcertDate < DateTime.Now).
Sum(Function(r) r.Attendance)
Nastier:
dt.AsEnumerable().
Where(Function(r) DateTime.ParseExact(ro("ConcertDate"), "dd.MM.yyyy") < DateTime.Now).
Sum(Function(r) r.Field(Of Integer)(Attendance))
You can use this strongly typed datatable anywhere you would use a normal datatable - you can still access it by string column names etc if you desperately wanted to:
someDatagridview.DataSource = dt
someDataAdapter.Fill(dt)
MessageBox.Show(dt.Rows(0)("Id").ToString())
But it's very helpful to have intellisense be able to guide you and stay in strongly typed land:
MessageBox.Show(dt.First().Id.ToString())
As pointed out in the comments, I was using "dd/MM/yyyy" when my data comes in as "20.02.2021".
I used "dd.MM.yyyy" and it works.

iam trying to get datable specific columns which has null value using linq in vb.net get only those 2 empty rows

When I check the column values in a DataTable using LINQ, they are not equal. Here is the code I'm using which has the problem:
for eg if columnA 5 rows which two or empty ir null i should
DT.
Select("Source <> ('AMEX','VISA')").
ToList().
ForEach(Sub(row) row(ColumnExpType)="T")
To get all the rows, using LINQ, which have NULL in ColumnA you could do something like this:
DT.Rows().
Cast(Of DataRow).Where(Function(row) row("ColumnA") Is DBNull.Value)
However, depending on your needs, you may prefer to use the old Select method:
DT.Select("ColumnA IS NOT NULL")
If you also need to check if the column contains an empty string, then to do that with Select:
DT.Select("ColumnA IS NOT NULL OR ColumnA = ''")
But, if you want to use LINQ, then it depends on the type of the column and whether it's a typed DataTable (a table from a typed DataSet). If the column is a standard string type, like NVARCHAR in T-SQL, and the DataTable is just a standard non-typed DataTable, then you could do something like this:
DT.Rows().
Cast(Of DataRow).
Where(Function(row) row("ColumnA") Is DBNull.Value Or DirectCast(row("ColumnA"), String) = "")
Select("Source <> ('AMEX','VISA')") will not work.
You need
Select("Source <> 'AMEX' And Source <> 'VISA'")
Not sure what the For Each is doing. This is a working example of using my test database.
Dim lst = dt.Select("Rating <> 'Unrated' And Rating <>'Good'").ToList
For Each dr As DataRow In lst
Debug.Print(dr("Name").ToString)
Next

Dataview filtering vb.net

Wondering if I am doing this filter right with the dataview, it keeps throwing me this error
Additional information: Filter expression '80' does not evaluate to a Boolean term.
but here is the code
Dim table = DataSet1.Tables("network")
table.DefaultView.RowFilter = TextBox1.Text
DataGridView1.DataSource = table
To filter something on a DataVIew you need to specify the column on which the filter should be applied, the operator for the comparison and the value that you want to use for the filtering. It seems that you have given only the value "80".
For example, assuming the column of interest is named "NumberOfPieces" and you have typed 80 in the textbox
Dim table = DataSet1.Tables("network")
table.DefaultView.RowFilter = "NumberOfPieces = " & TextBox1.Text
DataGridView1.DataSource = table
This will filter the view with all the rows that have the value (a numeric value) equals to 80 in the column "NumberOfPieces". You could use other operators like Greater/Lesser Than ( >= <= ) or more complex construct that are well detailed in the MSDN page about the Expression property of the DataColumn object

Datatable Sorting From A Custom Number Sequence

My datatable has a field that has values like so..
0000006685-001
0000006685-002
0000006713-001
0000006714-002
0000006713-002
0000006697-002
I want the datatable to be re-ordered by this field so the numbers on the left of the hyphen go in order, followed by the corresponding sequence in order. So the above example data would be ordered like..
0000006685-001
0000006685-002
0000006697-002
0000006713-001
0000006713-002
0000006714-002
Dim dv As New DataView(parsedDataset.Tables("Detail"))
dv.Sort = "the field"
Dim dt As DataTable = dv.ToTable
The easiest way is, most probably, through the Select method then the CopyToTable method
dt = dt.Select("", "ColumnName ASC").CopyToDataTable
Replace ColumnName with the name of the column for that field.

VB.Net - Efficient way of de-duplicating data

I am dealing with a legacy application which is written in VB.Net 2.0 against a SQL 2000 database.
There is a single table which has ~125,000 rows and 2 pairs of fields with similar data.
i.e. FieldA1, FieldB1, FieldA2, FieldB2
I need to process a combined, distinct list of FieldA, FieldB.
Using SQL I have confirmed that there are ~140,000 distinct rows.
Due to a very restrictive framework in the application I can only retrieve the data as either 2 XML objects, 2 DataTable objects or 2 DataTableReader objects. I am unable to execute custom SQL using the framework.
Due to a very restrictive DB access policy I am unable to add a View or Stored Proc to retrieve as a single list.
What is the most efficient way to combine the 2 XML / DataTable / DataTableReader objects into a single, distinct, IEnumerable object for later processing?
I may have missed something here but could you not combine both DataTables using Merge?
DataTableA.Merge(DataTableB)
You can then use DataTableA.AsEnumerable()
Then see this answer on how to remove duplicates or
You can do this with a DataView as follows: dt.DefaultView.ToTable(True,[Column names])
This is the solution I came up with.
Combine the 2 DataTables using .Merge (thanks to Matt's answer)
Using this as a base I came up with the following code to get distinct rows from the DataTable based on 2 columns:
Private Shared Function GetDistinctRows(sourceTable As DataTable, ParamArray columnNames As String()) As DataTable
Dim dt As New DataTable
Dim sort = String.Empty
For Each columnName As String In columnNames
dt.Columns.Add(columnName, sourceTable.Columns(columnName).DataType)
If sort.Length > 0 Then
sort = sort & ","
End If
sort = sort & columnName
Next
Dim lastValue As DataRow = Nothing
For Each dr As DataRow In sourceTable.Select("", sort)
Dim add As Boolean = False
If IsNothing(lastValue) Then
add = True
Else
For Each columnName As String In columnNames
If Not (lastValue(columnName).Equals(dr(columnName))) Then
add = True
Exit For
End If
Next
End If
If add Then
lastValue = dr
dt.ImportRow(dr)
End If
Next
Return dt
End Function