C# DataTable LINQ & GROUP BY - c#

I have a DataTable with 20 columns (I only need 3 of them.) I need to perform the following query on it and then save the results as an array. I've done some searching, but I can't figure out how to perform the mathematical operation. I know LINQ should be used, but I'm not getting anywhere. Any help is greatly appreciated!
SELECT DISTINCT columnZ, (columnX + columnY) / 2 FROM DataTable
*EDIT - corrected SQL statement

Answering your last comment (I suggest you update the question):
var result =
(from row in dataTable.AsEnumerable()
let average = ((double)row["columnX"] + (double)row["columnY"])/2
select new
{
ColumnZ = (string)row["columnZ"],
Average = average
}).Distinct();
Use your actual data types.

Related

check if values are in datatable

I have an array or string:
private static string[] dataNames = new string[] {"value1", "value2".... };
I have table in my SQL database with a column of varchar type. I want to check which values from the array of string exists in that column.
I tried this:
public static void testProducts() {
string query = "select * from my table"
var dataTable = from row in dt.AsEnumerable()
where String.Equals(row.Field<string>("columnName"), dataNames[0], StringComparison.OrdinalIgnoreCase)
select new {
Name = row.Field<string> ("columnName")
};
foreach(var oneName in dataTable){
Console.WriteLine(oneName.Name);
}
}
that code is not the actual code, I am just trying to show you the important part
That code as you see check according to dataNames[index]
It works fine, but I have to run that code 56 times because the array has 56 elements and in each time I change the index
is there a faster way please?
the Comparison is case insensitive
First, you should not filter records in memory but in the datatabase.
But if you already have a DataTable and you need to find rows where one of it's fields is in your string[], you can use Linq-To-DataTable.
For example Enumerable.Contains:
var matchingRows = dt.AsEnumerable()
.Where(row => dataNames.Contains(row.Field<string>("columnName"), StringComparer.OrdinalIgnoreCase));
foreach(DataRow row in matchingRows)
Console.WriteLine(row.Field<string>("columnName"));
Here is a more efficient (but less readable) approach using Enumerable.Join:
var matchingRows = dt.AsEnumerable().Join(dataNames,
row => row.Field<string>("columnName"),
name => name,
(row, name) => row,
StringComparer.OrdinalIgnoreCase);
try to use contains should return all value that you need
var data = from row in dt.AsEnumerable()
where dataNames.Contains(row.Field<string>("columnName"))
select new
{
Name = row.Field<string>("columnName")
};
Passing a list of values is surprisingly difficult. Passing a table-valued parameter requires creating a T-SQL data type on the server. You can pass an XML document containing the parameters and decode that using SQL Server's convoluted XML syntax.
Below is a relatively simple alternative that works for up to a thousand values. The goal is to to build an in query:
select col1 from YourTable where col1 in ('val1', 'val2', ...)
In C#, you should probably use parameters:
select col1 from YourTable where col1 in (#par1, #par2, ...)
Which you can pass like:
var com = yourConnection.CreateCommand();
com.CommandText = #"select col1 from YourTable where col1 in (";
for (var i=0; i< dataNames.Length; i++)
{
var parName = string.Format("par{0}", i+1);
com.Parameters.AddWithValue(parName, dataNames[i]);
com.CommandText += parName;
if (i+1 != dataNames.Length)
com.CommandText += ", ";
}
com.CommandText += ");";
var existingValues = new List<string>();
using (var reader = com.ExecuteReader())
{
while (read.Read())
existingValues.Add(read["col1"]);
}
Given the complexity of this solution I'd go for Max' or Tim's answer. You could consider this answer if the table is very large and you can't copy it into memory.
Sorry I don't have a lot of relevant code here, but I did a similar thing quite some time ago, so I will try to explain.
Essentially I had a long list of item IDs that I needed to return to the client, which then told the server which ones it wanted loaded at any particular time. The original query passed the values as a comma separated set of strings (they were actually GUIDs). Problem was that once the number of entries hit 100, there was a noticeable lag to the user, once it got to 1000 possible entries, the query took a minute and a half, and when we went to 10,000, lets just say you could boil the kettle and drink your tea/coffee before it came back.
The answer was to stick the values to check directly into a temporary table, where one row of the table represented one value to check against. The temporary table was keyed against the user who performed the search, so this meant other users searches wouldn't become corrupted with each other, and when the user logged out, then we knew which values in the search table could be removed.
Depending on where this data comes from will depend on the best way for you to load the reference table. But once it is there, then your new query will look something like:-
SELECT Count(t.*), rt.dataName
FROM table t
RIGHT JOIN referenceTable rt ON tr.dataName = t.columnName
WHERE rt.userRef = #UserIdValue
GROUP BY tr.dataName
The RIGHT JOIN here should give you a value for each of your reference table values, including 0 if the value did not appear in your table. If you don't care which one don't appear, then changing it to an INNER JOIN will eliminate the zeros.
The WHERE clause is to ensure that your search only returns the unique items that you are looking for at the moment - the design should consider that concurrent access will someday occur here (even if it doesn't at the moment), so writing something in to protect it is advisable.

Linq Result Join all Rows Data to string

I am getting data like 200k records from the database and store it in a linq result with a ColumnName EMAIL. Now,I want to show all emails from the linq result and adding them to a TextBox by separating with a ,.
Actually,I have prepared DataTable with that linq result and have combined all row data with the code :
var dataLists = (from xx in VDC.SURVEY_EMAIL_LIST
where xx.EMAIL_GROUP_ID == ListGroupID
select xx).ToList();
DataTable DtDataLists = LINQToDataTable(dataLists);
EmailIDS = string.Join(",", DtDataLists.AsEnumerable().Select(x => x["EMAILID"].ToString()).ToArray());
But,for preparing DataTable,it is taking a long time.
So,I thought of preparing the string EmailIDS directly from the linq result.
Can anyone help me?
This code should work for you but I'm not sure that it'll be much faster:
string.Join(",", dataLists.Select(x => x.EMAILID));

Get sum from a DataColumn values in C#

I have a table in a dataadapter. I want to get the count and sum of a specific column of it. How is that possible?
This is the code for reach to the column, what after that?
DataColumn buy_count = myDataSet.Tables["all_saled"].Columns["how_much_buy"]
I know that we have sum, count,... in SQL, but how can I do it in C#?
You can use LINQ to DataSets
var sales = myDataSet.Tables["all_saled"].AsEnumerable();
var buy_total = sales.Sum(datarow => datarow.Field<int>("how_much_buy"));
Check the LINQ to DataSets 101 Samples
P.S. might need the System.Data.DataSetExtensions assembly referenced.
Use the DataTable.Compute method:
int total = (int)myDataSet.Tables["all_saled"].Compute("SUM(how_much_buy)", null);

Querying inside a Dataset C#

I have an ADO.NET dataset which is set by a certain query,
say
SELECT ID,USER,PRODUCT,COUNT FROM PRODUCTION
Without using a where clause I need to derive some results from the dataset. Say I want to get the User and Product count of the user who has the maximum product count. (And I want to do it by using the existing dataset. I can't derive this from dataset.)
Any idea of a way to query inside the dataset? Since there are Datatables my thought was there is some way to query it.
Traditional SQL queries cannot be applied to the DataSet. The following is possible, however:
Filter rows using DataTable.Select. See here for detailed information about expressions in DataTables.
Calculate totals etc. using DataTable.Compute.
If these two don't do the trick, there's always LINQ.
Quick-and-dirty LINQ example: (which doesn't return a DataTable, but a list containing an anonymous type):
var joinedResult = dataTable1
// filtering:
.Select("MyColumn = 'value'")
// joining tables:
.Join(
dataTable2.AsEnumerable(),
row => row.Field<long>("PrimaryKeyField"),
row => row.Field<long?>("ForeignKeyField"),
// selecting a custom result:
(row1, row2) => new { AnotherColumn = row1.Field<string>("AnotherColumn") });
AsEnumerable converts a DataTable into an IEnumerable on which LINQ queries can be performed. If you are new to LINQ, check out this introduction.
Yes, you can use DataTable.Select method.
DataTable table = DataSet1.Tables["Orders"];
// Presuming the DataTable has a column named Date.
string expression;
expression = "Date > #1/1/00#";
DataRow[] foundRows;
// Use the Select method to find all rows matching the filter.
foundRows = table.Select(expression);
// Print column 0 of each returned row.
for(int i = 0; i < foundRows.Length; i ++)
{
Console.WriteLine(foundRows[i][0]);
}
Also see this link.
You can do cross-table queries of a Dataset object using LINQ to DataSet:
msdn.microsoft.com/en-us/library/bb386969.aspx

C#: retrieve the first n records from a DataTable

I have a DataTable that contains 2000 records.
How would you retrieve the first 100 records in the DataTable?
If it implements IEnumerable<T>:
var first100 = table.Take(100);
If the type in question only implements IEnumerable, you can use the Cast extention method:
var first100 = table.Cast<Foo>().Take(100);
This works for DB2.
select * from table
fetch first 100 rows only;
and for mysql: select * from table limit 100
You could use something like this, but restrict the foreach loop to 100 records.
And to make the list full, here is the statement for MS SQL:
Select top 5 * from MyTable2
And some other methods with MS SQL can be found here.
To get a list of the top n records in C# using the 2.0 framework:
DataTable dt = new DataTable();
var myRows = new List<DataRow>();
//no sorting specified; take straight from the top.
for (int i = 0; i < 100; i++)
{
myRows.Add(dt.Rows[i]);
}

Categories

Resources