SUM child column of tableadapter - c#

I have a tableadapter (SettlementCurrentTableAdapter) with a relation. parent table is (SettlementCurrent) child table is (Trips).
I need to SUM each row (tripLoadedMiles) in (Trips) and display the total in a label (labelWelcomeSetTotalMiles).
I would like to do this in code and not sql as i use this tableadapter to display other labels.
Can someone help me figure this out. i am new to C# and i use Visual C#.
this.settlementCurrentTableAdapter.Fill(this.myLeaseDataSet.SettlementCurrent);
MyLeaseDataSet.SettlementCurrentRow settlementCurrent;
settlementCurrent = myLeaseDataSet.SettlementCurrent.Last();
var settlementCurrentID = settlementCurrent.setID;
this.tripsTableAdapter.FillByTripSetID(this.myLeaseDataSet.Trips, settlementCurrentID);
MyLeaseDataSet.TripsDataTable settlementTrips;
settlementTrips = myLeaseDataSet.Trips;
foreach (DataRow row in myLeaseDataSet.Trips.Rows)
{
NOT SURE ON THE CODE HERE
}

Your first step is to extract the data you want out of your data adapter. Since I don't have a table model in your question, it is best to look at the table adapter overview on MSDN, and click on the related links and articles to figure out the basic usage of this object. If you were to post your table structure, I could theoretically give you some code for it, but I'm reluctant to do that - you will have to work with this object a lot of it's how you're talking to your database, so it's imperative you learn how it functions.
Your goal in this learning is to figure out how to get all the miles figures out of your table adapter. You usually do this by going over one row at a time, and picking out the values you want to add them to a more C# idiomatic data structure, such as a a List/IEnumerable, or an Array.
After you have the data you need in one of these structures, you can get the sum of everything by using LINQ. Depending on how much you pulled out, it can be as simple as one call (if this is something like an Array of ints):
var totalMiles = tripLoadedMiles.Sum();
Or as elaborate as you might need (if this is a List of a custom object that has both SettlementCurrentId and Miles, both stored as ints):
var totalMiles = tripLoadedMiles.Select(x => x.SettlementCurrentId == someRandomRequiredSettlement).Sum(y => y.Miles);
In the way you're using things, this is how you're looking at totaling it in this situation.
var total = 0;
foreach (DataRow row in myLeaseDataSet.Trips.Rows)
{
total += int.Parse(row["tripTotalMiles"].ToString());
}
// Use the total

Related

C# chart - difficulty plotting time series with different frequencies

This is my first post on here. I'm attempting to create a 'simple' charting program (windows form based in c#). I say simple because I'm currently only playing around with only 2 series maximum, and a few transformations (percent changes, actual changes, moving averages and moving sums). It will get more complicated than this but having the limited functionality first might help me get a better handle on how all of this works in C#.
I've been searching on and off for a couple of days now but have had no luck so far with my specific situation. I'll try to be as detailed as possible. The user retrieves the time series data from a SQL Server. This part of the program is behaving as expected. I'm creating 2 queries (one for each series) to retrieve the data separately. I do the transformations in the SQL query. Each comes via a SQL adapter which is then placed into a data table. The series may be of different frequencies and the dates may not overlap (i.e. sometimes a stock prices will be daily, and exports will be monthly, or GDP quarterly). The exports number may come in as the first of every month, while stock prices may be missing a value on this date if it was a weekend. I suspect this part is important for my issue.
Nonetheless, I double checked this step and everything works as expected (the values are all coming in correctly at the right dates).
To add those series to a chart, I merge the two data tables like so (I believe this is where my issues are coming from):
myTable = myTables1.Copy();
myTables1.PrimaryKey = new DataColumn[] { myTables1.Columns["dates"] };
myTables2.PrimaryKey = new DataColumn[] { myTables2.Columns["dates"] };
myTable.Merge(myTables2, true);
Datagridview of the Merged data table here looks good to me
Then I create the chart: I've tried two different methods here. The first is to create each series in a 2 step loop (one for each series) and loop through each row in the table and add an x and y value for each series. I've also tried to set the data source for the chart to be the table, and create 2 series and set the X and Y members as the names of the columns in the table.
Like so:
mychart.DataSource = myTable;
Then in a loop for each series:
mychart.Series.Add(seriesname);
mychart.Series[seriesname].XValueMember = "dates";
mychart.Series[seriesname].YValueMembers = seriesname;
Regardless, my second series is always a bit off. Either there are straight lines going across or it misses some values (and by adding a tool tip i can tell that the dates where one series may have a value while the other does not, is where the problems are occurring).
I'm not looking for help with syntax (just ideas). So my question is: is there a standard or preferred way of getting and plotting series with different frequencies (or which may have different x values)? Alternatively, is there a good source/documentation where i can read up on this? I would add that i have a similar program using visual basic which uses one SQL query regardless of how many series there are. This works in terms of the chart looking as I'd expect it to, but it makes transformations much more complicated given the randomness of the null or empty values in the final table.

Remove duplicate values from ListView with the lower TIME value?

I have a listview control that is filled with returned records from a SQL Statement. The fields may be something like:
SSN------|NAME|DATE----|TIME--|SYS
111222333|Bell|20140130|121507|P
123456789|John|20140225|135000|P
123456789|John|20140225|135002|N
The "duplicates" are generated from a ChangeLog, such as a change of address. Due to bad database design I have no control over however, an address change will create 2 records if a member happens to be a member of both SYS.
What would be the best way to go through each record in my listview, find duplicate values of SSN & DATE (There can be a record generated for both SYS if person is a member of both), and remove the duplicate value with the lower TIME value?
I'm trying to do a code-based solution instead of SQL because the true SQL statement is already highly complex and this application needs to only be maintained until October.
For this, I've assumed you have some class with these record's properties exposed with easy access like SSN and Time, I've also assumed they were both strings. In the code below I refer to this object as Record.
HINT: You might instead want to be removing items with the SYS flag set to False instead of judging it on time (Probably doesn't make a difference) .
I did not used any lambda fun on purpose to try to keep this simple and easy to read.
Call this code every time you load items into the ListView.... it would actually be a better idea to sanitize that list before you load it into the ListView, but the below code is a solution to your question based on the available info.
//Turn the ListView's ItemCollection into an easy to use List<Record>
List<Record> records = myListView.Items.OfType<Record>().ToList();
//Grab records with duplicate SSNs but with lower Time values
List<Record> recordsToRemove = new List<Record>();
foreach (var record in records)
{
foreach (var r in records)
{
if (record.SSN == r.SSN && record != r)
{
if (int.Parse(r.Time) > int.Parse(record.Time))
recordsToRemove.Add(record);
else
recordsToRemove.Add(r);
}
}
}
//Now actually remove the items from the ListView
foreach (var record in recordsToRemove)
{
myListView.Items.Remove(record);
}

Parallel.For maintain input list order on output list

I'd like some input on keeping the order of a list during heavy-duty operations that I decided to try to do in a parallel manner to see if it boosts performance. (It did!)
I came up with a solution, but since this was my first attempt at anything parallel, I'd need someone to slap my hands if I did something very stupid.
There's a query that returns a list of card owners, sorted by name, then by date of birth. This needs to be rendered in a table on a web page (ASP.Net WebForms). The original coder decided he would construct the table cell-by-cell (TableCell), add them to rows (TableRow), then each row to the table. So no GridView, allegedly its performance is bad, but the performance was very poor regardless :).
The database query returns in no time, the most time is spent on looping through the results and adding table cells etc.
I made the following method to maintain the original order of the list:
private TableRow[] ComposeRows(List<CardHolder> queryResult)
{
int queryElementsCount = queryResult.Count();
// array with the query's size
var rowArray = new TableRow[queryElementsCount];
Parallel.For(0, queryElementsCount, i =>
{
var row = new TableRow();
var cell = new TableCell();
// various operations, including simple ones such as:
cell.Text = queryResult[i].Name;
row.Cells.Add(cell);
// here I'm adding the current item to it's original index
// to maintain order in the output list
rowArray[i] = row;
});
return rowArray;
}
So as you can see, because I'm returning a very different type of data (List<CardHolder> -> TableRow[]), I can't just simply omit the ordering from the original query to do it after the operations.
Also, I also thought it would be a good idea to Dispose() the objects at the end of each loop, because the query can return a huge list and letting cell and row objects pile up in the heap could impact performance.(?)
How badly did I do? Does anyone have a better solution in case mine is flawed?
After testing, with a |2000| array, StopWatch says parallel composition is done in 63 ms (165082 ticks), and serial composition is done in 267 ms (698222). Both including adding rows to- (table.Rows.AddRange()), then rendering the Table. Without adding and rendering, times are 33ms/87541t for parallel and 178ms/467068t for serial.
A little code-review:
the 2 calls to Dispose() should be removed. At best they are harmless.
take a critical look at how you obtain originalIndex. It should always turn out to be equal to i so you don't need it.
But aside from this bit of streamlining there is not much to improve. It is doubtful that doing this in parallel will help much, or that this is the real bottleneck in your code. I suspect most time will be spent processing the results in TableRow[] .

Displaying a single value from a one to many relationship in a GridView

I have 3 tables:
Order,
OrderStates,
OrderStateDefinition
An Order has many OrderStates which then has one OrderStateDefinition.
I have a gridview in which I am trying to display only one value inside the OrderStates collection - the latest OrderState that has been added.
I've read a little about subqueries but I'm unsure about how to go about achieving the result I want.
Sorry bout the lack of information, I had a nice picture all set up of the table structure but stackoverflow wouldn't let me upload it.
Edit -
OK I figured out how to do this. As the GridView was being populated I used the event OnRowCreated to then set the text of the field I required. To get to the control I needed I used the e.Row.FindControl.
The code for it was pretty simple in the end. I always seem to figure this stuff out when I finally ask for help.
try
{
int orderID = e.Row.RowIndex;
Order order = ShopEntities.Orders.Single(o => o.OrderStateID == orderID);
// I can now get the list of orderstates
OrderStateDefinition osd = order.OrderStates.OrderBy(o => o.Date).Last().OrderStateDefinition;
((Label)e.Row.FindControl("Label2")).Text = osd.State;
}
catch
{
}
I often find it's easier to create your own SQL that does this. the sql might be a little complex, but it's easier than mucking with the c#.

Join multiple DataRows into a single DataRow

I am writing this in C# using .NET 3.5. I have a System.Data.DataSet object with a single DataTable that uses the following schema:
Id : uint
AddressA: string
AddressB: string
Bytes : uint
When I run my application, let's say the DataTable gets filled with the following:
1 192.168.0.1 192.168.0.10 300
2 192.168.0.1 192.168.0.20 400
3 192.168.0.1 192.168.0.30 300
4 10.152.0.13 167.10.2.187 80
I'd like to be able to query this DataTable where AddressA is unique and the Bytes column is summed together (I'm not sure I'm saying that correctly). In essence, I'd like to get the following result:
1 192.168.0.1 1000
2 10.152.0.13 80
I ultimately want this result in a DataTable that can be bound to a DataGrid, and I need to update/regenerate this result every 5 seconds or so.
How do I do this? DataTable.Select() method? If so, what does the query look like? Is there an alternate/better way to achieve my goal?
EDIT: I do not have a database. I'm simply using an in-memory DataSet to store the data, so a pure SQL solution won't work here. I'm trying to figure out how to do it within the DataSet itself.
For readability (and because I love it) I would try to use LINQ:
var aggregatedAddresses = from DataRow row in dt.Rows
group row by row["AddressA"] into g
select new {
Address = g.Key,
Byte = g.Sum(row => (uint)row["Bytes"])
};
int i = 1;
foreach(var row in aggregatedAddresses)
{
result.Rows.Add(i++, row.Address, row.Byte);
}
If a performace issue is discovered with the LINQ solution I would go with a manual solution summing up the rows in a loop over the original table and inserting them into the result table.
You can also bind the aggregatedAddresses directly to the grid instead of putting it into a DataTable.
most efficient solution would be to do the sum in SQL directly
select AddressA, SUM(bytes) from ... group by AddressA
I agree with Steven as well that doing this on the server side is the best option. If you are using .NET 3.5 though, you don't have to go through what Rune suggests. Rather, use the extension methods for datasets to help query and sum the values.
Then, you can map it easily to an anonymous type which you can set as the data source for your grid (assuming you don't allow edits to this, which I don't see how you can, since you are aggregating the data).
I agree with Steven that the best way to do this is to do it in the database. But if that isn't an option you can try the following:
Make a new datatable and add the columns you need manually using DataTable.Columns.Add(name, datatype)
Step through the first datatables Rows collection and for each row create a new row in your new datatable using DataTable.NewRow()
Copy the values of the columns found in the first table into the new row
Find the matching row in the other data table using Select() and copy out the final value into the new data row
Add the row to your new data table using DataTable.Rows.Add(newRow)
This will give you a new data table containing the combined data from the two tables. It won't be very fast, but unless you have huge amounts of data it will probably be fast enough. But try to avoid doing a LIKE-query in the Select, for that one is slow.
One possible optimization would be possible if both tables contains rows with identical primary keys. You could then sort both tables and step through them fetching both data rows using their array index. This would rid you of the Select call.

Categories

Resources