This is a fairly simple question, though I am unsure of exactly how to go about it. I'm doing a query on a database, then inserting the pulled value into a textbox. However the query could return a null value, here is my problem. If the query returns a null then the textbox should display 19. I'm unsure of how to check the returned data to determine if null was returned so that 19 can be inserted into the textbox. here is my code (it works putting the returned value into the textbox its missing the check for null/add 19)
using (test1 ds = new test1())
{
DataTable dt = ds.dataset.Tables[0];
List<string> coolList = new List<string>();
foreach (DataRow row in dt.Rows)
{
coolList.Add(row[0].ToString());
}
textBox7.Text = string.Join(" ", coolList);
}
Better not use null. Simple write in your SQL: SELECT IsNull(YourColumn, 19) as YourColumn FROM WhatEver. Than you have solved your problem directly in sql.
string rowString = !String.IsNullOrEmpty(row[0].ToString()) ? row[0].ToString() : "19";
coolList.Add(rowString);
You can use String.IsNullOrWhiteSpace instead if you're using .NET 4 or newer.
Instead of creating a List<string> , you can use LINQ to DataSet/DataTable like:
textBox7.Text = string.Join(" ",
dt.AsEnumerable()
.Select(r => string.IsNullOrWhiteSpace(r.Field<string>(0))
? "19"
: r.Field<string>(0)));
Using ISNULL is whatcha need to handle this.
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 DataTable (Ado.Net) with column 'Status'. This column holds the values (in each records)
['Red','Green','Blue','Yellow','White','OtherColors']
I want to select all the rows which status value not Red,Green,Blue
What the kind of filter expression to use to select data with my proposed criteria. So i want to achive some thing like we used in sql query ( WHERE Status NOT IN ('Red','Green','Blue')
NB:This project is running .NET 2.0 i cant use linq
I have tested it, it works as desired:
DataRow[] filtered = tblStatus.Select("Status NOT IN ('Red','Green','Blue')");
The resulting DataRow[] contains only DataRows with OtherColors, Yellow and White.
If you could use LINQ i'd prefer that:
string[] excludeStatus = {"Red","Green","Blue"};
var filteredRows = tblStatus.AsEnumerable()
.Where(row => !excludeStatus.Contains(row.Field<string>("Status")));
Without Linq you can use the rowfilter of a DataView like this
public DataTable GetFilteredData(DataTable table, string[] filterValues)
{
var dv = new DataView(table);
var filter = string.join("','", filterValues);
dv.RowFilter = "Status NOT IN ('" + filter + "')";
return dv.ToTable();
}
Supposing your datatable is part of a typed dataset you can use Linq to datasets, from which you could something like:
var records =
from record in datatable
where !record.Status.Contains('Red','Green','Blue')
select record;
Even if you don't have a typed dataset Linq to datasets is your answer. You would need to some casting, but not to difficult.
I currently have a DataTable with the following columns: Date, X1, Y1, Z1, X2, Y2, Z2... Xn, Yn, Zn.
When populated, Date ALWAYS has a value, and X/Y/Z1 to X/Y/Zn can be DBNull, a string, or an int. If the entire row with the exception of Date, is DBNull, i would like to remove that particular row.
I am currently doing an exhaustive search, looping through each row with a for loop, and then with a nested for loop, checking each cell, if i do not find any data (ie. only dbnull's), i then call RemoveAt, and reset the outer loop to start at zero again.
Is there a better/less hacky way of performing this operation? The initial building of the datatable cannot be modified, this must be something that happens post building.
If I understand correctly, you want to remove a row if all columns has DbNull.Value.
Try the following to do that.
DataTable table = new DataTable();
string[] columns = table.Columns.Cast<DataColumn>()
.Select(x => x.ColumnName)
.Skip(1)//skip to ignore first column
.ToArray();
Method1:
Remove all invalid rows
var invalidRows = table.AsEnumerable()
.Where(x => columns.All(c => x.Field<object>(c) == DBNull.Value))
.ToArray();
foreach (var row in invalidRows)
{
table.Rows.Remove(row);
}
Method2: take only valid rows and make new DataTable as suggested my #Tim in comments to improve performance when you have many invalid rows
var newTable = table.AsEnumerable()
.Where(x => columns.Any(c => x.Field<object>(c) != DBNull.Value))
.CopyToDataTable();
ATTENTION : THESE ARE MY EXAMPLES>>NOT EXCATLLY FOR YOUR TABLE>>>SO CHANGE IT FOR YOURSELF
The Main Help is Here >> Help
And Then
Way one :
dtData.Select("ID=1 AND ID2=3");
Way two :
GridFieldDAO dao = new GridFieldDAO();
//Load My DataTable
DataTable dt = dao.getDT();
//Get My rows based off selection criteria
DataRow[] drs = dt.Select("(detailID = 1) AND (detailTypeID = 2)");
//make a new "results" datatable via clone to keep structure
DataTable dt2 = dt.Clone();
//Import the Rows
foreach (DataRow d in drs)
{
dt2.ImportRow(d);
}
//Bind to my new DataTable and it will only show rows based off selection
//criteria
myGrid.DataSource = dt2;
myGrid.DataBind();
And The best Way is :
DataTable tblFiltered = table.AsEnumerable()
.Where(row => row.Field<String>("Nachname") == username
&& row.Field<String>("Ort") == location)
.OrderByDescending(row => row.Field<String>("Nachname"))
.CopyToDataTable();
May be this will help you. Try this
var ordered = yourdatatable.AsEnumerable().Where(x => x.Field<DateTime>("ColumnName") != null);
if (ordered.Count() > 0)
{
yourdatatable= orderedCopyToDataTable();
}
you can do the same for other columns as well.
Or
Why don't you check for the null values in your query. check for ISNULL(columnName, value) As ColumnName. Check more details here
You can use this little Linq query:
var columnsWithoutDate = table.Columns.Cast<DataColumn>().Skip(1);
table = table.AsEnumerable()
.Where(row => columnsWithoutDate.Any(col => !row.IsNull(col)))
.CopyToDataTable();
Skip(1) returns all columns but the first, so your date column is excluded. The Where enumerates all DataRows in the table and takes all rows with at least one non-null field(see:DataRow.IsNull(column)). Finally CopyToDataTable creates a new DataTable.
I would go for something like this:
var test = from row in table.AsEnumerable()
where (!row.IsNull("col1") || !row.IsNull("col2"))
select row;
//option1
DataTable dt = test.CopyToDataTable<DataRow>();
//option2
DataTable dt2 = new DataTable();
dt2.Columns.Add("col1", typeof(String));
dt2.Columns.Add("col2", typeof(Int32));
foreach (var v in test)
{
DataRow dr = dt2.NewRow();
dr["col1"] = v.Field<String>("col1");
dr["col1"] = v.Field<Int32>("col2");
dt2.Rows.Add(dr);
}
Did you try using RowFilter of DataTable?
DataTable dt = GetData();
//set the filter
dt.DefaultView.RowFilter = "----your filter----";
//then access the DataView
foreach (DataRowView drv in dt.DefaultView)
{
//you can also get a row from rowview
DataRow dr = drv.Row;
}
Check this documentation, they also explain how to handle null values in filters.
http://msdn.microsoft.com/en-us/library/system.data.dataview.rowfilter.aspx
You can also use Select() method with same filter, refer the below answer there is a good comparison on both approach.
DataView.RowFilter Vs DataTable.Select() vs DataTable.Rows.Find()
I would not suggest using AsEnumerable() approach, though looks like simple code but it is just like doing a foreach loop on rows and having IF conditions.
DataTable filter approach should be faster than AsEnumerable() (I am not sure, but I am assuming this because DataTable is .net's powerful data structure to handle tabular data)
modified answer:
myDataTable.AsEnumerable().Where(a => a.ItemArray.Count(b=>b != DBNull.Value)==1).ToList().ForEach(row => dataTable.Rows.Remove(row));
I checked, it works.
EDIT:
in response to #Tim Schmelter comment:
1 . you need myDataTable.AsEnumerable() in C#
If you have a strongly typed DataTable, you do not. I assumed it's the case, since OP says:
The initial building of the datatable cannot be modified, this must be
something that happens post building.
Maybe I did't understand what he meant (my English sometimes fails me)
2 . count the non-null fields is incorrect since a string can be null
which is not the same as if it is DBNull.Value(also according OP's
specifications)
You are probably right. If OP says he only wants DBNull, the second condition should be removed (it's a bad habit of mine to check for null just in case)
3 . ToList creates another List which is redundant
Yes. And if there's no ToList(), ForEach() can't be used. The old fashioned foreach can be used instead, or beter for loop (since foreach doesn't like when you try to modify collection inside it). Still you have to keep your result in some way.
4 . DataRow.Delete does it not remove from the table what is desired,
but it flags it as deleted for a DataAdapter(OP's has not mentioned
that he's using one, it is also not desired).
Thank you for pointing that out.
I have a DataTable dt with 2 columns. First col (call it CustomerId) is unique and doesn't allow nulls. the second one allows nulls and is not unique.
From a method I get a CustomerId and then I would like to either insert a new record if this CustomerId doesn't exist or increment by 1 what's in the second column corresponding to that CustomerId if it exists.
I'm not sure how I should approach this. I wrote a select statement (which returns System.Data.DataRow) but I don't know how to test whether it returned an empty string.
Currently I have:
//I want to insert a new row
if (dt.Select("CustomerId ='" + customerId + "'") == null) //Always true :|
{
DataRow dr = dt.NewRow();
dr["CustomerId"] = customerId;
}
If the datatable is being populated by a database. I would recommend making the customerid a identity column. That way when you add a new row it will automatically create a new customerid which will be unique and 1 greater than the previous id (depending on how you setup your identity column)
I would check the row count which is returned from the select statement. Something like
I would also use string.Format...
So it would look like this
var selectStatement = string.Format("CustomerId = {0}", customerId);
var rows = dt.Select(selectStatement);
if (rows.Count < 1){
var dr = dt.NewRow();
dr["CustomerId"] = customerId;
}
This is my method to solve similar problem. You can modify it to fit your needs.
public static bool ImportRowIfNotExists(DataTable dataTable, DataRow dataRow, string keyColumnName)
{
string selectStatement = string.Format("{0} = '{1}'", keyColumnName, dataRow[keyColumnName]);
DataRow[] rows = dataTable.Select(selectStatement);
if (rows.Length == 0)
{
dataTable.ImportRow(dataRow);
return true;
}
else
{
return false;
}
}
The Select Method returns an array of DataRow objects. Just check if its length is zero (it's never null).
By the way, don't write such statements in the code directly as in this example. There's a technique for breaching your code's security called "SQL Injection", I encourage you to read the Wikipedia Article. In brief, an experienced user could write SQL script that gets executed by your database and potentially do harmful things if you're taking customerId from the user as a string. I'm not experienced in database programming, this is just "general knowledge"...
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.