calculate rank from student marks stored in datatable in vb. net - vb.net

I am working on examination result system in vb.net which requires to calculate student ranks based on marks obtained. Subject marks data is stored in database. I am loading the subject marks in a datatable
da.Fill(dt) 'added to a datagridview.
DataGridView1.DataSource = dt
then Add New columns in dt to show result:
dt.Columns.Add("Obtained Marks", GetType(String))
dt.Columns.Add("Percent", GetType(String))
dt.Columns.Add("Result", GetType(String))
dt.Columns.Add("Rank", GetType(Integer))
Then calculated total of all the subjects & added in obtained marks columns by looping through rows & columns of datatable.
For s As Integer = 0 To dt.Rows.Count - 1
For t As Integer = 0 To dt.Columns.Count - 1
obtmarks += CDbl(dt.Rows(s).Item(t))
Next
dt.Rows(s)("Obtained Marks") = obtmarks
dt.Rows(s)("Result") = "PASS"
dt.Rows(s)("Rank") = 'RANK OF STUDENT
Next
How can i calculate rank/position of students on the basis of total marks contained in datatable column "Obtained Marks".
i.e.
Student with marks 436 Rank should be 1
Student with marks 429.5 Rank should be 2
Student with marks 412 Rank should be 3 ....
so on until all the rows in record. (Image atttached)
if there is any function for datatable which can help here or how can i add the logic in the loop to calculate rank of students and add the value in rank column. Thanks
P.S. I dnt want to sort the rows on obtained marks, but want to Add rank of each student in front of his/her marks, which is already order by their Roll No.

You could use this code to set the Rank column in your table
DataView dv = new DataView(dt, "", "ObtainedMarks desc", DataViewRowState.CurrentRows);
for(int x = 0; x < dv.Count; x++)
dv[x].Row["Rank"] = x+1;
This could be done only after you have completed the code that calculates the column ObtainedMarks
Also, I suggest to execute all before setting the DataSource of the DataGridView to avoid unnecessary delays in the grid repainting itself when you have not yet finished with it
EDIT
To have the same rank for persons with the same marks you could try something like this
int lastMark = -1;
int currentRank = 0;
int atSameRank = 1;
DataView dv = new DataView(dt, "", "ObtainedMarks desc", DataViewRowState.CurrentRows);
for(int x = 0; x < dv.Count; x++)
{
int currentMark = Convert.ToInt32(dv["ObtainedMarks"]);
if(currentMark != lastMark)
{
lastMark = currentMark;
currentRank = currentRank + atSameRank;
atSameRank = 0;
}
else
atSameRank++;
dv[x].Row["Rank"] = currentRank;
}
WARNING, I am not at a PC where I could test it.

Related

BigInteger Innacuracy

In the following project euler program #56, Considering natural numbers of the form, a^b, where a, b < 100, what is the maximum digital sum?
so I wrote the following code:
Dim num As System.Numerics.BigInteger
Dim s As String
Dim sum As Integer
Dim record As Integer
For a = 2 To 99
For b = 1 To 99
num = a ^ b
s = num.ToString
For i = 0 To s.Length - 1
sum += CInt(s.Substring(i, 1))
Next
sum = 0
Next
Next
The answer I got from the program was not the correct answer, so I wrote the following code so I can see what numbers set a new high value and see if something is wrong.
If sum > record Then
record = sum
Console.WriteLine(a & "," & b)
End If
One of the answers was a=10 b= 81. Obviously that doesn't make sense, because that value is 1 + 81 "0" = 1, but watching the result of 10^81, was 999999999999999921281879895665782741935503249059183851809998224123064148429897728
I searched about the accuracy of BigInteger but couldn't find anything, is there something that I'm missing?

Charting Sales Order stats

I have a datatable that has the columns: Order Number, a count of Lines, and a sum of Units. I want to end up with charts shown here. 3 charts Each shows a column for 1 through 20 and then >20
The problem is looping through the datatable takes over 1.5 minutes.
Dim XAxis(21) As String
Dim LinesPO(21) As Integer 'Lines per Order
Dim UnitsPO(21) As Integer 'Units Per Order
Dim UnitsPL(21) As Integer 'Units Per Line
For Each Dr As DataRow In LivesqlDt2.Rows
For i = 0 To 21
If i < 21 Then
XAxis(i) = i.ToString
If Dr.Item("Lines") = i Then LinesPO(i) += 1
If Dr.Item("Units") = i Then UnitsPO(i) += 1
If Math.Round(Dr.Item("Units") / Dr.Item("Lines"), 0) = i Then UnitsPL(i) += 1
Else
XAxis(i) = ">20"
If Dr.Item("Lines") >= i Then LinesPO(i) += 1
If Dr.Item("Units") >= i Then UnitsPO(i) += 1
If Math.Round(Dr.Item("Units") / Dr.Item("Lines"), 0) >= i Then UnitsPL(i) += 1
End If
Next
Next
I'm looking for any good ideas to speed this up, because the salesman wants to be able to run this in front of their customer.

How to run same query on every single row of a table? (MVC)

I'm currently having a table named 'Events' where there are columns 'EquipApprovedDate', 'EquipCalDueDate', & 'ThemeColor'. I want to update the ThemeColor based on the remaining days left before the EquipCalDueDate.
Green = Good
Orange = Considered okay
Red = Critical
The total days will be different for every equipment registered on the calendar. It will be calculated by using this formula (totaldays = EquipCalDueDate - EquipApprovedDate). The remaining days will be calculated using this formula (remainingDays = EquipCalDueDate - DateTime.Now).
If remainingDays is more than 2/3 of totaldays it will be labelled 'green'.
If remainingDays is less than 2/3 of totaldays but more than 1/3 of totaldays it will be labelled 'orange'.
If remainingDays is less than 1/3 of totaldays it will be labelled 'red'.
I want to apply this whole process on table every time the page is loaded, specifically on each and every single row found in the database. Basically to collect the data and return it for every single row. For now it's only running partially where the column ThemeColor is being updated to 'green' for every single row no matter what. What is the correct SQL query?
I have attached my current work together for your view.
con.Open();
string yyy = "SELECT * FROM [Events]";
using (SqlCommand cmd = new SqlCommand(yyy, con))
{
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
String startdate = reader["EquipApprovedDate"].ToString();
DateTime Sdate = DateTime.Parse(startdate);
String enddate = reader["EquipCalDueDate"].ToString();
DateTime Edate = DateTime.Parse(enddate);
String themecolor = reader["ThemeColor"].ToString();
double totaldays = (Edate - Sdate).TotalDays;
double remainingDays = (Edate - DateTime.Now).TotalDays;
if (remainingDays > (totaldays * (2 / 3)))
{
string sqlCoC = "UPDATE Events SET ThemeColor = 'green'";
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MVCConnectionString"].ConnectionString))
{
SqlCommand coccmd = new SqlCommand(sqlCoC, con);
con.Open();
coccmd.ExecuteNonQuery();
con.Close();
}
//green = means good
}
else if ((remainingDays < (totaldays * (2 / 3))) && (remainingDays > (totaldays * (1 / 3))))
{
string sqlCoC = "UPDATE Events SET ThemeColor = 'orange'";
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MVCConnectionString"].ConnectionString))
{
SqlCommand coccmd = new SqlCommand(sqlCoC, con);
con.Open();
coccmd.ExecuteNonQuery();
con.Close();
}
//orange = considered okay
}
else if (remainingDays < (totaldays * (1 / 3)))
{
string sqlCoC = "UPDATE Events SET ThemeColor = 'red'";
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MVCConnectionString"].ConnectionString))
{
SqlCommand coccmd = new SqlCommand(sqlCoC, con);
con.Open();
coccmd.ExecuteNonQuery();
con.Close();
}
//red = critical
}
else { }
}
reader.Close();
con.Close();
}
You can actually do the entire table update with one query:
declare #remaining int, #total int; update events
set #remaining=datediff(day, getdate(), equipcalduedate),
#total=datediff(day, equipapproveddate, equipcalduedate),
themecolor=(case
when #remaining < #total/3 then 'red'
when #remaining < 2*#total/3 then 'orange'
else 'green'
end)
For the sample data you provided (plus one other value I added to demonstrate 'orange' theme color, the output data from a select:
select EventId, EquipApprovedDate, EquipCalDueDate, ThemeColor, datediff(day, getdate(), equipcalduedate) as remaining,
datediff(day, equipapproveddate, equipcalduedate) as total
from events
looks like this, which I think is what you want:
EventId EquipApprovedDate EquipCalDueDate ThemeColor remaining total
1 2018-04-17 2018-05-31 green 36 44
2 2018-04-11 2018-04-27 red 2 16
3 2020-04-20 2020-05-28 green 764 38
4 2018-04-11 2018-05-15 orange 20 34
8 2019-04-20 2019-05-31 green 401 41

Modify Avg lookupset in SSRS to remove null

I have the follow custom function that I am using in an SSRS report in order to calculate an average value using the LookUpSet function. I have a number of results in the set that are returned that are null. At the moment this function is taking these as 0 and increasing the count. How would I modify this to exclude the 0 values so that it just skips them and keeps the count the same. ie. just excludes them completely from the dataset that is returned?
Function AvgLookup(ByVal items As Object()) As Decimal
If items Is Nothing Then
Return Nothing
End If
Dim suma As Decimal = New Decimal()
Dim ct as Integer = New Integer()
Dim Avg as Decimal = New Decimal()
suma = 0
ct = 0
For Each item As Object In items
suma += Convert.ToDecimal(item)
ct += 1
Next
Avg = suma / ct
If (ct = 0) Then return 0 else return Avg
End Function
It seems the easiest way would be to add a IF statement in your loop. This assumes it is converting the NULLS to 0 and you have no 0 values you want.
For Each item As Object In items
IF Convert.ToDecimal(item) <> 0
suma += Convert.ToDecimal(item)
ct += 1
ENDIF
Next

How to create a virtual column on a gridview based on a particular gridview columns

Please i have a project that i query the database using entity framework as my ORM. This is my query
Dim subjectSearch = From subSearch In DemoSchool.EssenceSubjectRegistrations Where subSearch.Session = drpSession.SelectedItem.Text _
AndAlso subSearch.Term = drpTerm.SelectedItem.Text AndAlso subSearch.RealClass.ClassSN = findClassSN.FirstOrDefault AndAlso _
subSearch.SubjectCode = drpSubject.SelectedValue _
Select New With {.SubjectRegSN = subSearch.SubjectRegSN,
.FirstName = subSearch.Student.FirstName,
.Surname = subSearch.Student.Surname,
.CA1 = subSearch.CA1,
.CA2 = subSearch.CA2,
.CA3 = subSearch.CA3,
.CA4 = subSearch.CA4,
.CA5 = subSearch.CA5}
Then i query my result so that i can be able to do some operation on it by doing this
Dim secSubjectSearch = (From jamie In subjectSearch Select jamie).ToList() _
.Select(Function(jamie) New With {.SubjectRegSN = jamie.SubjectRegSN,
.FirstName = jamie.FirstName,
.Surname = jamie.Surname,
.CA1 = jamie.CA1,
.CA2 = jamie.CA2,
.CA3 = jamie.CA3,
.CA4 = jamie.CA4,
.CA5 = jamie.CA5,
.MidTerm = CDbl(jamie.CA1 + jamie.CA2 + jamie.CA3 + jamie.CA4 + jamie.CA5) / 5})
The result of the second query is bounded to the gridview which renders properly as it is suppose to rendered. My problem is that i want to create a virtual column called Rank on the gridview after the .MidTerm bounded column that will display the position of each person record in the search result.
NAME CA1 CA2 CA3 CA4 CA5 MIDTERM RANK
James 50 50 60 40 60 52 3
Essty 100 50 50 50 50 60 2
Markus 100 40 50 60 50 60 2
Code 100 100 100 100 50 90 1
Above is a format of the gridview columns. I want column Rank to be a virtual column that is calculated based on the Midterm score of the students.Code VB scored 90 so his rank so be 1 and so on.Please i don't know how to calculate this rank column and the code to get the highest and the smallest.Really i need help thanks
Two ways.
Use Unbound column and calculate/display the rank
Have a RANK field and pre-calculate it and bound it, something like:
Dim secSubjectSearch = (From jamie In subjectSearch Select jamie).ToList() _
.Select(Function(jamie) New With {.SubjectRegSN = jamie.SubjectRegSN,
.FirstName = jamie.FirstName,
.Surname = jamie.Surname,
.CA1 = jamie.CA1,
.CA2 = jamie.CA2,
.CA3 = jamie.CA3,
.CA4 = jamie.CA4,
.CA5 = jamie.CA5,
.MidTerm = CDbl(jamie.CA1 + jamie.CA2 + jamie.CA3 + jamie.CA4 + jamie.CA5) / 5,
.RANK = -1}).ToList()
dim sorted = secSubjectSearch.Select(function(n) n.MidTerm).Distinct().OrderByDescending(function(n) n).ToList()
for each itm in secSubjectSearch
itm.RANK = sorted.IndexOf(itm.MidTerm) + 1
next
-- Not tested, wrote it with notepad...