I am building LINQ to SQL and its run against SQlite database. I need to remove repeating column values from the dataset. Basically the value would be shown for the first row in the dataset and blanked for each subsequent row that had the same value.
I read about using break but I am not sure how to write it up or if it can be used. I read other threads addressing the same issue but was not able to come up with a solution for my scenario.
Should I just retrieve the dataset and suppress them in C# code?
If so I need help/pointers to do that.
If you are displaying this data in an SSRS report (.RDLC), set the HideDuplicates property of the text box that shows the data to either the name of the dataset or the grouping it's in (to show the value at the start of a new group).
You could loop through the result and set a local variable of
string lastValue = null;
foreach(var row in rows)
{
if(lastValue == row.SomeColumn)
{
row.SomeColumn = null;
}
else
{
lastValue = row.SomeColumn
}
}
Probably others ways, but hard to say without more context of what you have so far.
Have you tried using Linq to get the values from your table using the Distinct Method?
Related
I need to go through a database finding all text-like fields, checking for a particular set of URLs that might be in these fields and modify it using some regex.
The actual text manipulation part is fine, but since I'm generically going through tables, some of which seem to not have primary keys, I'm wondering how to update these rows once I've read this. I'll give a dummy example below.
foreach(var matchingTable in tables){
foreach(var matchingColumn in columns){
SqlCommand currentCommand = new SqlCommand("select * from #matchingTable;");
currentCommand.Parameters.AddWithValue("#matchingTable", matchingTable);
using (SqlDataReader reader = currentCommand.ExecuteReader())
{
while (reader.Read())
{
if(/* logic to check reader[matchingColumn]*/){
/*edit row to change column matchingColumn, a row which I can't be sure has any uniquely identifying factor*/
}
}
}
}
}
Is it possible to edit this arbitrary row or will I have to change how I'm doing this?
If a table do not have guaranteed unique id then there is no value of a duplicated record. And so if a duplicated record is also updated then no harm will be done.
You can consider all the fields as one composite field and perform the update.
One thing to keep in mind is the duplicate records will also be updated.
This might be easier to solve inside the database. You can write a cursor equivalent to the two for-loops to select the table and column. From there you can write a simple UPDATE/WHERE using your regular expression.
I am trying to read all new rows that are added to the database on a timer.
First I read the entire database and save it to a local data table, but I want to read all new rows that are added to the database. Here is how I'm trying to read new rows:
string accessDB1 = string.Format("SELECT * FROM {0} ORDER BY ID DESC", tableName);
setupaccessDB(accessDB1);
int dTRows = localDataTable.Rows.Count + 1;
localDataTable.Rows.Add();
using (readNext = command.ExecuteReader())
{
while (readNext.Read())
{
for (int xyz = 0; xyz < localDataTable.Columns.Count; xyz++)
{
// Code
}
break;
}
}
If only 1 row is added within the timer then this works fine, but when multiple rows are added this only reads the latest row.
So is there any way I can read all added rows.
I am using OledbDataReader.
Thanks in advance
For most tables the primary key is based an incremental value. This can be a very simple integer that is incremented by one, but it could also be a datetime based guid.
Anyway if you know the id of the last record. You can simple ask for all records that have a 'higher' id. In that way you do get the new records, but what about updated records? If you also want those you might want to use a column that contains a datetime value.
A little bit more trickier are records that are deleted from the database. You can't retrieve those with a basic query. You could solve that by setting a TTL for each record you retrieve from the database much like a cache. When the record is 'expired', you try to retrieve it again.
Some databases like Microsoft SQL Server also provide more advanced options into this regard. You can use query notifications via the broker services or enable change tracking on your database. The last one can even indicate what was the last action per record (insert, update or delete).
Your immediate problem lies here:
while (readNext.Read())
{
doSomething();
break;
}
This is what your loop basically boils down to. That break is going to exit the loop after processing the first item, regardless of how many items there are.
The first item, in this case, will probably be the last one added (as you state it is) since you're sorting by descending ID.
In terms of reading only newly added rows, there are a variety of ways to do it, some which will depend on the DBMS that you're using.
Perhaps the simplest and most portable would be to add an extra column processed which is set to false when a row is first added.
That way, you can simply have a query that looks for those records and, for each, process them and set the column to true.
In fact, you could use triggers to do this (force the flag to false on insertion) which opens up the possibility for doing it with updates as well.
Tracking deletions is a little more difficult but still achievable. You could have a trigger which actually writes the record to a separate table before deleting it so that your processing code has access to those details as well.
The following works
using (readNext = command.ExecuteReader())
{
while (readNext.Read())
{
abc = readNext.FieldCount;
for (int s = 1; s < abc; s++)
{
var nextValue = readNext.GetValue(s);
}
}
}
The For Loop reads the current row and then the While Loop moves onto the next row
I'm currently working with a utility that was written using the Infragistics WebDataGrid control. The tool allows a user to select a table from a drop-down list at which point it runs a stored procedure to get data from SQL Server which it then binds to the grid.
Everything gets a default format, which for datetime columns is simply MM/DD/YYYY in this case. There is a request to include the time component for at least one of these columns.
After much searching I've tried to add code to the _InitializeRow event handler for the grid, but I can't seem to get it quite right. Here's what I've come up with:
if (e.Row.Index == 0)
{
foreach (GridRecordItem field in e.Row.Items)
{
if (field.Column.Key == "InsertedOnCC")
field.Column.FormatValue = "{0:g}";
}
}
This gives me an error that FormatValue cannot have a value assigned because it is a method group.
This was pieced together from several sources, none of which did quite what I wanted to do. For example, one piece of sample code just always assumed that the column in question was the first column, so I had to add the foreach loop.
I've seen a lot of mention of BoundDataField and DataFormatString, but I can't seem to actually find how to access those.
NOTE: I'm actually a SQL Developer, not a C# developer, so please be gentle. :)
Thanks!
I was able to sort this out by casting the Column as a BoundDataField then using the DataFormatString from there:
if (e.Row.Index == 0)
{
foreach (GridRecordItem gri in e.Row.Items)
{
BoundDataField field = gri.Column as BoundDataField;
if (field.Key == "InsertedOnCC")
field.DataFormatString = "{0:g}";
}
}
Using the info above, I was able to get this to work. It's cleaner. It does not require the loop:
TryCast(.Rows(0).Items.FindItemByKey("MyColumnName").Column, Infragistics.Web.UI.GridControls.BoundDataField).DataFormatString = "{0:G}"
I have been trying for hours to get the info in my datagridview to save to the datatable. The datagridview is populated from a combobox where selections are made. What I cant figure out is how to convert the qty_Ordered to int. I believe it will work once I have that.
Also, is it possible to use the column names of the datagridview rather than Cells[]?
foreach (DataGridViewRow row in purchase_Order_ItemsDataGridView.Rows)
{
if (!row.IsNewRow)
{
SQL = #"INSERT INTO Purchase_Order_Items (Purchase_Order_ID, Part_Number, Qty_Ordered, Work_Order_Number)
VALUES(#purchase_Order_Id, #part_Number, #qty_Ordered, #work_Order_Number)";
sqlCommand = new SqlCommand(SQL, DataAccessClass.sql_Connection);
sqlCommand.Parameters.AddWithValue("#purchase_Order_ID", purchase_Order_Id);
sqlCommand.Parameters.AddWithValue("#part_Number", row.Cells[1].Value);
sqlCommand.Parameters.AddWithValue("#qty_Ordered", row.Cells[2].Value);
sqlCommand.Parameters.AddWithValue("#work_Order_Number", row.Cells[3].Value);
sqlCommand.ExecuteNonQuery();
}
}
Have you tried this? Admittedly a stopgap solution but it does convert it to int.
sqlCommand.Parameters.AddWithValue("#qty_Ordered", int.parse(row.Cells[2].Value.ToString()));
edit: This link might help you more -
Get Numeric Value from DataGridViewCell?
It deals with ways to convert the cell with a bit more robustness than the above solution, would would fail dramatically when your value is null.
edit 2: Looks like the above solution isn't robust enough. The below code is more robust.
int qtyordered;
if (!int.TryParse(row.Cells[2].Value.ToString(), out qtyordered)
qtyordered = 0;
sqlCommand.Parameters.AddWithValue("#qty_Ordered", qtyordered);
Loathing's answer would work the best since it'd work transparently with your current code, however it's a bit tricky. You need to expose the datatable's column so that you can modify the type. And you need to do that when / after the column has been created and before you begin adding data.
purchase_Order_ItemsDataGridView.Columns[2].ValueType = typeof(int);
You need to put this somewhere early on, before you begin populating the table but after you created the columns.
I'm trying to mimic the functionality of the Query Analyzer piece of the SQL Server Management Studio using .NET. The user will input a SQL script, and the program will run it. If it returns a result set, the program will load that up into a datagrid and show the user.
My question is: Is there a way to return more than one result set from a single script? I know Query Analyzer runs this and loads up multiple datagrids if several result sets are returned, but as far as I know when you try to do this with SqlDataAdapter.Fill(...), it only returns the last result set in the script.
This will show you how to return multiple result sets: http://vb.net-informations.com/ado.net-dataproviders/ado.net-multiple-result-sets.htm
You loop through the different result sets using the sqlReader.NextResult() method. You can then use sqlReader.Read() to get each individual record in that result set.
You can call SqlDataAdapter.Fill passing in a DataSet. Each query result will populate a table in the DataSet:
When the query specified returns multiple results, the result set for each row returning query is placed in a separate table. Additional result sets are named by appending integral values to the specified table name (for example, "Table", "Table1", "Table2", and so on).
I think I might have figured this out. Sometimes writing the problem out helps you understand it better, and then fresh ideas start to pop up :)
I had been using the SqlDataAdapter.Fill(...) method to fill a DataTable. As it turns out, if you fill an empty DataSet it will automatically create a table for each result set returned. So, I can have a few hidden datagrids on hand and when the program detects that the DataSet filled has multiple tables, then I'll just load up each datagrid with data from each DataTable in the DataSet.