I have a datatable that has a column "Pending Approval Number". I need to get the highest number in that column to display to a user as the next available. I have seen some examples of how to do this but I have not been able to get them to work. I know i could loop each DataRow in the DataTable and check the value and store it if it is higher than the last. But I know there has to be a better way.
Here is how the DataTable is filled.
strSQL = "Select * from JobInvoice";
DataTable dtApprovalNumber = new DataTable();
MySqlDataAdapter daApprovalNumber = new MySqlDataAdapter(strSQL, conn);
daApprovalNumber.Fill(dtApprovalNumber);
A change to the SQL query or code to pull it from the datatable are both welcome.
EDIT: After getting the solution for my original numeric column, I found the second column that I need to do this for is string. The solution was also provided below.
If You want to get highest Value from DataTable in code not in sql, then You can just use linq like below:
int highestNumber = dtApprovalNumber.AsEnumerable().Max(x => x.Field<int>("SomeIntegerColumn");
EDIT.
According to Your comment - if You want to calculate max value from a string column which holds numbers(don't get it why) You can go with something like that:
int highestNumber = dtApprovalNumber.AsEnumerable().Max(x => int.Parse(x.Field<string>("SomeStringColumn")));
Please Note that if any of those string values is not convertable it will fail then You will have to do it other way.
EDIT.2
Since I've just tried it I'll share with You - the situation when You have string Column and You are not sure if all of them are convertable(for example some might be empty). See below:
int tempVariable;
int highestNumber = dt.AsEnumerable()
.Where(x => int.TryParse(x.Field<string>("SomeColumn"), out tempVariable))
.Max(m => int.Parse(m.Field<string>("SomeColumn")));
Select max(`Pending Approval Number`) from JobInvoice
You can do a maxvalue + 1 to show it as next available number.
Related
I have a datatable that I am trying to make an update on.
my datatable is the data source of a data gridview (Forms application)
I want to update all rows that are part of a textbox
the textbox contains a comma separated values such as
A1,A11,B4,B38,C44
I have this code but stuck on how to make it working
DataTable dt = new DataTable();
dt = (DataTable)grd1.DataSource;
DataRow[] dr = dt.Select("'," + TextBox1.Text + ",' LIKE '%,Code,%'");
foreach (DataRow row in dr)
{
row["Price"] = 1000;
}
The problem is in this code
"'," + TextBox1.Text + ",' LIKE '%,Code,%'"
it does not retuen any rows so I think I did not write it the right way.
How to fix my select line?
Note : I added a comma before and after so I do not get "T37" when I am looking for "T3"
Your question wasn't easy to understand for me, but you seem to be saying that you will type a list of values into the textbox and these values are to be looked up in the [Code] column of the datatable. I'm not clear on whether the Code column itself is a single value or a comma separated list of codes, so I'll answer for both. Assuming the Code column is a CSV, and you want that any row where any one of the values in Code is one of these values in the textbox, shall have its price updated to 1000:
So for a textbox of "A1,B1" and a datarows like:
Code Price
A1,C3 200
B4,C7 400
The 200 row shall be updated and the 490 row shall not
I'd use LINQ for this rather than datatable select
var codes = textbox.Split(',');
var rows = dt.AsEnumerable().Where(r => codes.Any(c => (r["Code"] as string).Split(',').Contains(c)));
foreach(var r in rows)
r["Price") = 1000;
If you're doing this a lot I wouldn't have the codes in the row as a CSV string; a row field is allowed to be an array of strings - storing the codes as an array in the row will save having to split them every time you want to query them
If I've got this wrong and the row contains just a single Code value, the logic is the same, it just doesn't need the split(though the code above would work, it's not optimal):
var rows = dt.AsEnumerable().Where(r => codes.Any(c => (r["Code"] as string) == c));
And actually if you're going to be doing this a lot, I would index the datatable:
//if it's a csv in the datatable
var index = dt.AsEnumerable()
.SelectMany(r => r["Code"].ToString().Split(','), (row, code) => new { R=row, C=code})
.ToLookup(o => o.C, o => o.R);
This will give something like a dictionary where a code maps to a list of rows where the code appears. For a row set like
Code Price
A1,C3 200
B4,C3 400
You get a "dictionary" like:
A1: { "A1,C3", 200 }
C3: { "A1,C3", 200 },{ "B4,C3", 400 }
B4: { "B4,C3", 400 }
so you could:
foreach(var c in codesTextbox.Split)
foreach(var row in index["c"])
row["Price"] = 1000;
If the Code column doesn't contain a csv, doing a selectmany should still be fine, but to optimize it:
var index = dt.AsEnumerable().ToLookup(r => (string)r["Code"]);
I have a problem with format in C#.
I have a DataGridView and a TextBox. In this datagridview, there is a column: the single price (format int).
I want sum every elements of single price's column and insert the result into this textbox, but Visual Studio gives me a problem with format of string input ("Format of input's string is not correct").
this is the code than i used:
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
TOT = TOT + Convert.ToInt32(dataGridView3.Rows[i].Cells[6].ToString());
}
textBoxTot.Text = Convert.ToString(TOT);
Can you help me with this bad error?
UPDATE:
I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
If your datagridview is showing a datatable (I.e. your data is stored in a datatable) you can add a DataColumn to the datatable whose .Expression property is set to the string "SUM([Price])", where Price is the name of your numeric datatyped column holding the price info.
Now every row in the table will have the sum of the prices (the same value over and over again), so if you want to databind your textBox to this new column then it will always show the sum no matter which row is the current row (because all rows have the same value). It will also auto update without you having to do anything!
And if you're not using databinding to a datatable, I recommend that you do do it, because it represents good MVC practice of keeping your data in one thing (DataTable) and showing it in another (DataGridView) and keeping these concerns separate
It would look something like this, as a quick example:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Price", typeof(int));
dt.Columns.Add("CalculatedTotal", typeof(int)).Expression = "SUM([Price])";
dt.Rows.Add("Apples", 100);
dt.Rows.Add("Oranges", 200);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
WhateverDataGridView.DataSource = bs;
totalTextBox.DataBindings.Add(new Binding("Text", bs, "CalculatedTotal", true));
Here we have a data model (the datatable) where we keep our data. It has a couple of things we can set directly, and an third column that calculates based on the existing prices in all the table. If you look at this in the datagridview (assuming you have autogeneratecolumns turned on) you'll see that both rows have 300 for the CalculatedTotal, but they have individual amounts for price. There is a device called a BindingSource that sits between the datatable and the UI controls; you don't have to have one but it makes certain things easier regards updating controls when the data changes, and it maintains a concept of "current" - essentially whatever the current row is you're looking at in the datagridview; it all helps to avoid having to ask the DGV for anything - we just let the user type into the DGV, and it shows the data out of the datatable. All our dealings can be with the datatable directly - if you wrote a button to loop through the table and double all the prices, the controls in the UI would just reflect the change automatically. The textbox is connected to the CalculatedValue column via databinding; whatever the current row is, the textbox will show the CalculatedValue. Because the CalculatedValue column has the same value on every row, and they always all update if any price changes, the total textbox will always show the total. Add another textbox bound to Name to see what I mean; as you click around the grid and select different rows to be the "Current" row, the Name will change but the total does not. In truth it is actually changing in the same way that Name is, it's just that because the actual numeric value is the same on every row the contents of the textbox look like they don't change
UPDATE: I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
}
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
It is weird that you are first converting to a string and then to an int.
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (!dataGridView3.Rows[i].IsNewRow &&
int.TryParse(dataGridView3.Rows[i].Cells[6].Value.ToString(), out int v))
TOT += v;
}
textBoxTot.Text = TOT.ToString();
EDIT: Edited for your updated question. You shouldn't ask question inside a question buy anyway:
string sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
decimal total = 0M;
using (MySqlConnection cn = new MySqlConnection(" your connection string here "))
using (MySqlCommand cmd = new MySqlCommand(sumQuery, cn))
{
cn.Open();
total = Convert.ToDecimal(cmd.ExecuteScalar());
cn.Close();
}
Console.WriteLine(total);
I have created,
DataTable date= new DataTable();
date.Columns.Add("datenmoth");
and made fill the column name "Month" with date as
Month(Column name)
05-oct-2014
06-Nov-2014
02-Dec-2014
02-jan-2015
01-feb-2015
20-mar-2015
and made fill my dynamic table
Now, i want this dynamic table data to be Reverse order
i need result in: based on month and year taking reverse order
Month(Column name)
20-mar-2015
01-feb-2015
02-jan-2015
02-Dec-2014
06-Nov-2014
05-oct-2014
Thank you.
Don't fill this table with strings but with DateTimes. If you use string as column-type you always have to convert it to a DateTime. Like here:
var dateInReversedOrder = date.AsEnumerable()
.OrderByDescending(r => DateTime.Parse(r.Field<string>("datenmoth")))
.CopyToDataTable();
That works but is inefficient and prone to localization issues (in future).
Sample data and (desired) result after sorting in descending order:
DataTable date = new DataTable();
date.Columns.Add("datenmoth");
date.Rows.Add("05-oct-2014");
date.Rows.Add("20-mar-2015");
I have a DataTable I am populating from SQL table with the following example columns
ID
Type
Value
I am populating the DataTable with rows which are of a certain type. I want to select the rows 10 - 20 from my resulting DataTable:
Connect conn = new Connect();
SqlDataAdapter da = new SqlDataAdapter(SQL, conn.Connection());
//Creates data
DataTable d = new DataTable();
da.Fill(d);
DataRow[] result = d.Select();
In the above code I have omitted the main SQL, and currently I have no select for my DataRow array. I cannot find a way to reference the row numbers.
So for instance I am looking for something like Select("rownum > X && rownum < Y")
I have searched here, and a number of other resources to no avail. Any clues would be really handy, or just a simple not possible.
It's always better to select only what you need from the database(f.e. by using the TOP clause or a window function like ROW_NUMBER) instead of filtering it in memory.
However, you can use Linq-To-DataSet and Enumerable.Skip + Enumerable.Take:
var rows = d.AsEnumerable()
.Skip(9).Take(11); // select rows 10-20 as desired (so you want 11 rows)
If you want a new DataTable from the filtered result use CopyToDataTable, if you want a DataRow[] use rows.ToArray().
I would just do the 'take' and 'skip' command and keep it simple:
d.Select().Skip(10).Take(10); // skips 10 rows, then selects ten after that.
This would be assuming you have the Linq using set (using System.Linq)
Currently I'm searching as below.
DataRow[] rows =
dataTable.Select("FieldName='"+
userInput + "'");
The problem here is whenever user provides an input with single quote ('), it throws error.
I can easily correct it by
DataRow[] rows =
dataTable.Select("FieldName='" +
userInput.Replace("'","''") + "'");
I'm worried what other user inputs might cause problem?
Here is the exact answer from honourable Mr. Jon Skeet.
#Ismail: It would be a good habit if we validate user input before using that in front end query or in back-end query.
So i think in your scenario you must have function like...
if(ValidateInput(userInput))
{
DataRow[] rows = dataTable.Select("FieldName='"+ userInput + "'");
}
and in validation you can do any check. right now you only want to check ' but in future, may be you will have to check some thing else.
and based on your need you can checge return type of validate function, if you want to modify input data then modify and return that else just return bool.
If you want to use DataTable.Select(filter) for data filter then you have to format/ignore or replace special character from filter statement and for that u will have to write more code. If you dont want to be panic for special character then you can use LINQ like
DataTable dataTable = new DataTable();
DataColumn dc = new DataColumn("FieldName");
dataTable.Columns.Add(dc);
DataRow dr = dataTable.NewRow();
dr[0] = "D'sulja";
dataTable.Rows.Add(dr);
string input = "D'sulja";
var result = from item in dataTable.AsEnumerable()
where item.Field<string>("FieldName") == input select item;
In this case, I think the single quote is the only character you have to worry about since it is used to delimit string values. For more information on expression syntax, see the MSDN entry for DataColumn.Expression (creating a filter expression uses the same rules as for the DataColumn.Expression property).
You don't indicate which version of C# you are using, but with LINQ, you can do this:
var rows = table.AsEnumerable()
.Where(r => r.Field<string>("Name") == "O'Hare")
.Select(r => r)
.ToArray();
One tradeoff is that you'll also need to check the RowState if you have any deleted rows in the DataTable, but it does provide another option.