Filter data from DataTable - c#

DataTable dtt = (DataTable)Session["ByBrand"];
var filldt = (dtt.Select("Price >= " + HiddenField1.Value + " and Price <= " + HiddenField2.Value + "")).CopyToDataTable();
this code is working fine when it found values in selected DataTable but it showing error when Values are not found in DataTable. So please tell me how to check if no record found.

Simply check if your Select returns anything?
DataTable dtt = (DataTable)Session["ByBrand"];
DataRow[] rows = dtt.Select("Price >= " + HiddenField1.Value + " and Price <= " + HiddenField2.Value + "");
if(rows.Length > 0)
{
var filldt = rows.CopyToDataTable();
}
Well, the Linq example from Tim is really nice, but to complete my answer.
The Select method returns Always a DataRow array also if there is no row selected, but then you cannot ask to build a datatable from this empty array. Think about it. What schema the CopyToDataTable should build for the resulting table if no rows are present in the array?

You have tagged Linq but you are using DataTable.Select which is an old method to filter a DataTable. Use Enumerable.Where and the strongyl typed Field extension method.
decimal priceFrom = decimal.Parse(HiddenField1.Value);
decimal priceTo = decimal.Parse(HiddenField2.Value);
var dtFiltered = dtt.AsEnumerable()
.Where(row => row.Field<decimal>("Price") >= priceFrom
&& row.Field<decimal>("Price") <= priceTo))
.CopyToDataTable();
Presuming that the type of the column is decimal, if it's a different type you need to use that in Field or convert it first.
Note that you need to add System.Linq(file) and a reference to System.Data.DataSetExtensions(project).
Update
but it showing error when Values are not found in DataTable
CopyToDataTable throws an exception if the input sequence is empty. In my opinion the best approach is to handle that case separately:
DataTable tblFiltered = dtt.Clone(); // clones only structure not data
var filteredRows = dtt.AsEnumerable()
.Where(row => row.Field<decimal>("Price") >= priceFrom
&& row.Field<decimal>("Price") <= priceTo));
if(filteredRows.Any())
{
tblFiltered = filteredRows.CopyToDataTable();
}
or this approach that might be more efficient since it doesn't need to use Any which can cause an additional full enumeration in worst case:
foreach(DataRow row in filteredRows)
{
tblFiltered.ImportRow(row);
}

Related

Averaging every column in a DataTable

I am currently using the following LINQ statement to pull certain data out of my DataTable
var possibleRows = _Data.Select("Distance > " + (location.Distance - delta) + " AND Distance < " + (location.Distance + delta));
I would like to end up with a DataRow that contains an average of every column that was in the select statement above without having to iterate through each column. I have over 100 columns and all the data is numeric. Is there a simple way to do this?
You could just do something like:
var rows = possibleRows.Cast<DataRow>();
var averages = table.Columns.Cast<DataColumn>()
.Select(col => new {
Column = col,
Average = rows.Average(row => (double)row[col])
}).ToList();
Note this assumes double throughout.
Note this doesn't result in a DataRow; it results in a List<>, where each item in the list has the column and that column's average.

How to filter datetime field in datatable disregarding the time value of it in C#

I tried this code:
(datagridview1.DataSource as DataTable).Select("date_time=" + Convert.ToDateTime(dtpDate.Text.ToString()));
but I thinks it still include the time and gets me error "Syntax error: Missing operand after '12' operator."
What I really want to happen is that filter the datetime field of datable disregarding the time of it, just the date.
Here is what my datagridview looks like:
1 1 1/24/2013 12:34 AM
1 2 1/24/2013 12:34 AM
2 3 1/24/2013 12:53 AM
3 1/25/2013 12:30 AM
4 1/25/2013 12:53 AM
5 4 1/25/2013 2:10 AM
6 5 1/25/2013 2:26 AM
7 6 1/25/2013 2:39 AM
8 7 1/25/2013 2:40 AM
Updated code:
datagridview1.DataSource = (datagridview1.DataSource as DataTable).AsEnumerable()
.Where(r => r.Field<DateTime?>("date_time").HasValue
&& r.Field<DateTime?>("date_time").Value.Date == dt.Date).CopyToDataTable();
Don't use strings when you want to compare dates. You can use Linq-To-DataTable and the strongly typed DataRow extension method Field. Then use the Date property of DateTime.
DateTime dt = DateTime.Parse(dtpDate.Text);
DataTable filteredRows = table.AsEnumerable()
.Where(r => r.Field<DateTime>("date_time").Date == dt.Date)
.CopyToDataTable();
Edit (according to your comment)
"Cannot cast DBNull.Value to type 'System.DateTime'. Please use a nullable type.
Then you have nulls in this field. Since the Field method supports nullable-types you can use it directly.
DataTable filteredRows = table.AsEnumerable()
.Where(r => r.Field<DateTime?>("date_time").HasValue
&& r.Field<DateTime?>("date_time").Value.Date == dt.Date)
.CopyToDataTable();
Edit So you get an exception when the table is empty. Yes, CopyToDataTable throws an InvalidOperationException when the source table is empty.
Note that perhaps you don't need to copy the result into a new DataTable at all. You could bind the query itself to the datasource property of the datagridview, so try to simply omit the CopyToDataTable.
var filteredRows = table.AsEnumerable()
.Where(r => r.Field<DateTime?>("date_time").HasValue
&& r.Field<DateTime?>("date_time").Value.Date == dt.Date);
datagridview1.DataSource = filteredRows;
Otherwise you could also check if the query returns anything:
DataTable table = new DataTable();
if(filteredRows.Any())
{
table = filteredRows.CopyToDataTable();
}
DataView dv = new DataView(Datatable1);
dv.RowFilter = "StartDate >= #" + DtpDateRangeFrom.Value + "# AND StartDate <= #" + DtpDateRangeTo.Value + "#";

Having trouble trying to implement a query on dataset/datatable

I have a data set say 'ds' which I populate from a table called tran_dtls ,
now I want to write a method to this data set(or the table in the data set 'dt'),which would effectively retrieve for me a scalar value having the same output as this query:
select sum(amt) from TRAN_DTLS
where GL_CODE='" + row["gl_code"].ToString() + "'
and SUB_CODE='" + row["sub_code"].ToString() + "'
and DBCR='C'"
Here amt,GL_code,SUb_code,DBCR are the columns in tran_dtls table, So what I want to do is select the sum of amount having various conditions ,I have never done anything like this before so I don't know even this would be possible or not
I don't think you can write SQL against a DataSet. But you can use LINQ:
var ds = new DataSet();
var tranDtls = new DataTable("tran_dtls");
tranDtls.Columns.Add("gl_code", typeof(string));
tranDtls.Columns.Add("amt", typeof(int));
var row = tranDtls.NewRow();
row["gl_code"] = "a";
row["amt"] = 1;
tranDtls.Rows.Add(row);
ds.Tables.Add(tranDtls);
var result = ds.Tables["tran_dtls"].AsEnumerable()
.Where(r => (string)r["gl_code"] == "a")
.Select(r => (int)r["amt"])
.Sum();

Select statamen of a Datarow array

I have the following code, first I filter by a foreign key, but then with that result I need to filter more with dates.
But I cant understand the syntax of the select() method of a datarow array given below.
UC021_WizardStepSelectUnitDataSet.WizardStepSelectUnits_UnitsSelectedInOtherAgreementsRow[] datarows =
_uc021_WizardStepSelectUnitDataSet.WizardStepSelectUnits_UnitsSelectedInOtherAgreements.Select(
"UnitId = " + row.UnitID).Cast
<UC021_WizardStepSelectUnitDataSet.WizardStepSelectUnits_UnitsSelectedInOtherAgreementsRow>().ToArray();
DataRow[] dr = _uc021_WizardStepSelectUnitDataSet.
WizardStepSelectUnits_UnitsSelectedInOtherAgreements.Select(
"UnitId = " + row.UnitID);
if (datarows.Length > 0)
{
dr.Select("");
}
The Select on DataTable is similar to a Where clause you add to a query, in this case its filtering the records matching the row.UnitID which is to be found under column UnitId of the DataTable.
You can add multiple conditions by using AND within select like
.Select("UnitId = " + row.UnitID+ " AND IsActive='Y'")

Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier

DataTable distinctTable = dTable.DefaultView.ToTable(true,"ITEM_NO","ITEM_STOCK");
DataTable dtSummerized = new DataTable("SummerizedResult");
dtSummerized.Columns.Add("ITEM_NO",typeof(string));
dtSummerized.Columns.Add("ITEM_STOCK",typeof(double));
int count=0;
foreach(DataRow dRow in distinctTable.Rows)
{
count++;
//string itemNo = Convert.ToString(dRow[0]);
double TotalItem = Convert.ToDouble(dRow[1]);
string TotalStock = dTable.Compute("sum(" + TotalItem + ")", "ITEM_NO=" + dRow["ITEM_NO"].ToString()).ToString();
dtSummerized.Rows.Add(count,dRow["ITEM_NO"],TotalStock);
}
Error Message: Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier.
Do anyone can help me out?
Thanks.
You might try this:
dTable.Compute("sum([" + TotalItem + "])","");
I.e enclose your column name in square brackets [ ]
The idea is from this post.
The problem is exactly about your DataType of the column. If you have a row with dynamically added columns without DataType like that (it may be a result of a manual calculation or cross-tab query-like)
myTable.Columns.Add("AddedColumn");
You will probably face with the column conversion issue.
Instead, If you change your add method with pointing DataType like below
myTable.Columns.Add("AddedColumn", typeof(System.Int32));
It will work I think. It's what I experienced & fixed before...
You want to write:
dTable.Compute("sum(CONVERT(ITEM_STOCK, 'System.Double'))",
"ITEM_NO='" + dRow["ITEM_NO"].ToString() + "'")
instead of:
dTable.Compute("sum(" + TotalItem + ")", "ITEM_NO="...
because it will translate to dTable.Compute("sum(value_of_TotalItem), "ITEM_NO="..., value_of_TotalItem is a double and is not a column name.
See DataTable.Compute
UPDATE:
try this:
DataTable distinctTable = dTable.Clone();
dTable.Columns.Add("ITEM_STOCK_D", typeof(Decimal),
"CONVERT(ITEM_STOCK, 'System.Decimal')");
foreach (DataRow dRow in dTable.Rows)
{
String itemNo = dRow["ITEM_NO"].ToString();
if(distinctTable.Select(String.Format("ITEM_NO = '{0}'",itemNo)).Length == 0)
{
double totalStock = Convert.ToDouble(dTable.Compute("SUM(ITEM_STOCK_D)",
String.Format("ITEM_NO = '{0}'", itemNo)));
distinctTable.Rows.Add(itemNo, totalStock.ToString());
}
}
dTable.Columns.Remove("ITEM_STOCK_D");
In my case the issue was with my query itself.
My query returned difference of two columns. Like, query="Select A,B,A-B from Table" and I was performing sum on datatable using compute function as dt.Compute("Sum(A-B)","").
So, datatable was unable to compute the sum of A-B column. I gave the difference column alias as query="Select A,B,(A-B) as AB from Table"
and dt.Compute("Sum(AB)","").
Thus, resolved the error.

Categories

Resources