Implementing COUNT() and ROUND() method in LINQ query - c#

For another example to get return data of a pivot table I'm defined a LINQ query to solve this problem. Well, now my question is how to count the values of a column?
Here the following C# Code:
var query = from q in db.DS
where q.datum >= fromDate && q.datum <= toDate
group q by q.quot_rate
into grp
select new
{
Grade = grp.Key,
Total = grp.Select(t => new { t.fon, t.quot_rate }).AsQueryable()
};
var rate = (from q in db.DS
select q.fon).Distinct();
DataTable dt = new DataTable();
dt.Columns.Add("Grade");
foreach (var r in rate)
{
dt.Columns.Add(r.ToString());
}
foreach (var q in query)
{
DataRow dr = dt.NewRow();
dr["Grade"] = q.grade; //round q_grade
foreach (var t in q.Total)
{
dr[t.fon] = t.quot_rate; //count t.quot_rate
}
dt.Rows.Add(dr);
}
return dt;
You can see the comments where the numbers have to ROUND() and COUNT().
How can I define this?
EDIT:
The output is currently as follows:
Grade | AB001 | AB002 | AB003 ...
90,045| 90,045| null | null
85,590| null | 85,590| 85,590
85,450| null | 85,450| null
84,901| null | 84,901| null
and I want the result as follows:
Grade | AB001 | AB002 | AB003 ...
90 | 1 | 0 | 0
86 | 0 | 1 | 1
85 | 0 | 2 | 0

So it appears that you actually want rounding to happen inside the query, so that you can do grouping by rounded values. So first part of the question can be answered as:
Grade = Math.Round(grp.Key),
Then the counts come out naturally as:
q.Total.Count()
However it seems that you actually want counts by rate items, so I would suggest something like that for each table row:
foreach (var r in rate)
{
dr[r] = q.Total.Count(x => x.fon == r);
}

Related

Splitting hierarchies from datatable

I have a datatable which contains multiple hierarchies with different heights which I need to split.
eg.
|---------------------|------------------|
| Account | Hierarchy Account|
|---------------------|------------------|
| 1 | |
|---------------------|------------------|
| 2 | 1 |
|---------------------|------------------|
| 3 | 1 |
|---------------------|------------------|
| 4 | 2 |
|---------------------|------------------|
| 5 | 3 |
|---------------------|------------------|
| 6 | |
|---------------------|------------------
| 7 | 6 |
|---------------------|------------------|
| 8 | 6 |
|---------------------|------------------|
Below is what I have tried so far.
private List<DataTable> SplitDataTablesOnHierarchy(DataTable dataTable)
{
List<DataTable> dataTablesList = new List<DataTable>();
List<string> listTemp = new List<string>();
var HierarchyAccounts = dataTable.AsEnumerable().Where(m => m.Field<string>("Hierarchy Account Number") == "");
foreach(var topAccount in TopAccounts )
{
//Check if account exists in Hierarchy Account Number
var topAccountExists = dataTable.AsEnumerable().Any(m => m.Field<string>("Hierarchy Account Number") == topAccount.Field<string>("Account Number"));
if (topAccountExists == true)
{
DataTable newDataTable = dataTable.Clone();
newDataTable.ImportRow(payerAccount);
dataTablesList.Add(newDataTable);
}
//Top Accounts found and added to tempList
}
//CreateDataTable with Top Accounts
foreach(DataTable dTable in dataTablesList)
{
bool bottomHierarchyReached = true;
var TempSearch = dTable.Rows;
while(bottomHierarchyReached)
{
foreach(DataRow account in TempSearch)
{
var rows = dataTable.AsEnumerable().Where(m => m.Field<string>("Hierarchy Account Number") == account.Field<string>("Account Number")).CopyToDataTable();
if(rows.Rows.Count == 0)
{
bottomHierarchyReached = false;
break;
}
else
{
TempSearch = rows.Rows;
dTable.Rows.Add(rows.Rows);
}
}
}
}
return dataTablesList;
}
My thought process above was to first find the highest accounts in the hierarchy, create new datatables with those accounts and then drill down and add the following levels to the relevant datatable recursively since I do not know the height of each hierarchy.
Found a solution by creating a tempList which keeps the all of the lower levels while searching through the level above.
Once the loop through the SearchList is done we assign the tempList to it.
And then search through the next level of the hierarchy.
foreach (DataTable dTable in dataTablesList)
{
bool bottomHierarchyReached = true;
var SearchList = dTable.AsEnumerable().Select(p=> new { HierarchyAccount = p.Field<string>("Hierarchy Account Number"),
Account = p.Field<string>("Account Number")
}).ToList();
var tempList = SearchList.ToList();
tempList.Clear();
while (bottomHierarchyReached)
{
tempList.Clear();
foreach (var account in SearchList)
{
var rows = dataTable.AsEnumerable().Where(m => m.Field<string>("Hierarchy Account Number") == account.Account);
if(rows.Count() == 0)
{
bottomHierarchyReached = false;
break;
}
else
{
tempList.AddRange(rows.AsEnumerable().Select(p => new {
HierarchyAccount = p.Field<string>("Hierarchy Account Number"),
Account = p.Field<string>("Account Number")
}).ToList());
foreach(var row in rows)
{
dTable.ImportRow(row);
}
}
}
SearchList = tempList.ToList();
}
}

Transform SQL Records to Object

Currently I am developing an application like SharePoint and I am encountering a difficult as followed.
I have a DB table to keep my contents like the following
+----+---------------+----------+---------+----------+--------------------------+
| ID | Content_type | List_ID | COL_ID | ITEM_ID | VALUE |
+----+---------------+----------+---------+----------+--------------------------+
| 1 | "Column" | 1 | 0 | | "ABC" |
| 2 | "Column" | 1 | 1 | | "DEF" |
| 3 | "Item" | 1 | 0 | 1 | "<VALUE OF Column ABC>" |
| 4 | "Item" | 1 | 1 | 1 | "<VALUE OF Column DEF>" |
+----+---------------+----------+---------+----------+--------------------------+
and I would like to display these record on the web using linq and C# like the following....
ITEM_ID |ABC |DEF
------------+---------------------+----------------------
1 |<VALUE OF Column ABC>|<VALUE OF Column DEF>
EDITED:
My questions are:
I would like to use the DB record stated as Column in the content_type field to be the DataColumn of a DataTable.
I would like to map all records in the DB stated as ITEM with the same Item_ID as 1 DataRow of a DataTable. The value field of each DB records will fall onto the column of the DataTable based on the Column ID.
Thanks for the help. I had make it by myself....
First get the records from DB where content_type = "Column" and use
these records to form a DataTable
Get all records from DB where content_typ= "Item" and re-group each item to a List where ITEM_id =
Map the Item.title = column of the DataTable and Items.value = value of the DataTable rows....
public static DataTable PopulateRec(int list_id, string web_app, string host_auth)
{
DataTable dt = new DataTable();
List Column = Get_Column(list_id, web_app, host_auth);
for (int i = 0; i < Column.Count(); i++)
{
DataColumn datacolumn = new DataColumn();
datacolumn.ColumnName = Column[i].ToString();
dt.Columns.Add(datacolumn);
}
List Items = Get_Item(list_id, web_app, host_auth);
if (Items.Count != 0)
{
int ItemCount = Convert.ToInt32((from Itms in Items
select Itms.Item_id).Max());
for (int j = 0; j <= ItemCount; j++)
{
dt.Rows.Add();
List IndvItem = (from Indv in Items
where Indv.Item_id == j
select Indv).ToList();
foreach (var val in IndvItem)
{
dt.Rows[j][val.title] = val.value;
}
IndvItem = null;
}
for (int k = 0; k < dt.Rows.Count; k++)
{
if (dt.Rows[k][0].ToString() == string.Empty)
{
dt.Rows[k].Delete();
}
}
}
Column = null;
Items = null;
return dt;
}
private static List Get_Column(int list_id, string web_app, string host_auth)
{
List content_db = new List();
List columnname = new List();
Config_DB_Context configdb = new Config_DB_Context("dms_config");
content_db = (from c in configdb.site_mapping
where c.host_auth == host_auth
&& c.web_app == web_app
select c.content_db).ToList();
for(int i = 0; i < content_db.Count(); i++)
{
Content_DB_Context contentdb = new Content_DB_Context(content_db[i]);
columnname = (from c in contentdb.content
where c.content_type == "Column"
&& c.list_id == list_id
select c.title).ToList();
}
content_db = null;
return columnname;
}
private static List Get_Item(int list_id, string web_app, string host_auth)
{
List content_db = new List();
List Itm = new List();
Config_DB_Context configdb = new Config_DB_Context("dms_config");
content_db = (from c in configdb.site_mapping
where c.host_auth == host_auth
&& c.web_app == web_app
select c.content_db).ToList();
for (int i = 0; i < content_db.Count(); i++)
{
Content_DB_Context contentdb = new Content_DB_Context(content_db[i]);
Itm = (from c in contentdb.content
where c.content_type == "Item"
&& c.list_id == list_id
select new MyItem
{
col_id = (int)c.column_id,
list_id = (int)c.list_id,
title = c.title,
value = c.value,
Item_id = (int)c.item_id,
hidden = c.hidden
}).ToList();
}
content_db = null;
return Itm;
}

How to find the min dates from the list of items?

I have a table structure like this
id | itemId | date |
1 | a1 | 6/14/2015
2 | a1 | 3/14/2015
3 | a1 | 2/14/2015
4 | b1 | 6/14/2015
5 | c1 | 6/14/2015
From this table structure I am trying to get all the distinct items that has min date. for e.g. I am trying to get id = 3,4 and 5.
I have tried following code but I couldn't
var items = (from i in _db.Items
//where min(i.date) // doesn't seem right
group i by i.itemID
into d select new
{
iId = d.Key,
}).Distinct();
Given your sample data, I would do this:
var query =
from i in _db.Items
group i by i.itemId into gis
let lookup = gis.ToLookup(x => x.date, x => x.id)
from x in lookup[gis.Min(y => y.date)]
select x;
var items = from i in _db.Items
group i.date by i.itemID
into d select new {
iId = d.Key, iDate = d.Min()
};

c# - Summarizing duplicate rows in datatable

I have a table and I want to sum up duplicate rows:
|name | n | |name | n |
|------+---| |------+---|
|leo | 1 | |leo | 3 |
|wayne | 1 | |wayne | 2 |
|joe | 1 | |joe | 1 |
|wayne | 1 |
|leo | 1 |
|leo | 1 |
I can delete it like this, but how to summarize?
ArrayList UniqueRecords = new ArrayList();
ArrayList DuplicateRecords = new ArrayList();
foreach (DataRow dRow in table.Rows)
{
if (UniqueRecords.Contains(dRow["name"]))
DuplicateRecords.Add(dRow);
else
UniqueRecords.Add(dRow["name"]);
}
foreach (DataRow dRow in DuplicateRecords)
{
table.Rows.Remove(dRow);
}
This is how you do it with a dictionary. Basically you create a dictionary from "name" to DataRow object and then sum up the DataRows' "n" property:
// create intermediate dictionary to group the records
Dictionary<string, DataRow> SummarizedRecords = new Dictionary<string, DataRow>();
// iterate over all records
foreach(DataRow dRow in table.Rows)
{
// if the record is in the dictionary already -> sum the "n" value
if(SummarizedRecords.ContainsKey(dRow["name"]))
{
SummarizedRecords[dRow["name"]].n += dRow["n"];
}
else
{
// otherwise just add the element
SummarizedRecords[dRow["name"]] = dRow;
}
}
// transform the dictionary back into a list for further usage
ArrayList<DataRow> summarizedList = SummarizedRecords.Values.ToList();
I think this can be done more elegantly (1 line of code) with LINQ. Let me think some more about it :)
Edit
Here is a Linq version, which however involves creating new DataRow objects, this may not be your intention - don't know:
ArrayList<DataRow> summarizedRecords = table.Rows.GroupBy(row => row["name"]) // this line groups the records by "name"
.Select(group =>
{
int sum = group.Sum(item => item["n"]); // this line sums the "n"'s of the group
DataRow newRow = new DataRow(); // create a new DataRow object
newRow["name"] = group.Key; // set the "name" (key of the group)
newRow["n"] = sum; // set the "n" to sum
return newRow; // return that new DataRow
})
.ToList(); // make the resulting enumerable a list
Thanks for your replies, another variant:
var result = from row in table.AsEnumerable()
group row by row.Field<string>("Name") into grp
select new
{
name = grp.Key,
n = grp.Count()
};

Sql Multiple Conditions Method

I've been trying to find a way of using multiple conditions with Sql, at the moment I am using Entity Framework. There is a very good chance that this is the only way to achieve what I want but I wondered if anyone knew a more efficient method.
Essentially I am using criteria to find the next row in the database which should be picked. For example lets use the 2 following conditions:
1) Field1 = A;
2) Field2 = B;
So in the following table:
| RowId | Field1 | Field2 |
| 0001 | A | B |
| 0002 | B | B |
| 0003 | C | C |
| 0004 | A | C |
I need to pick each row individually in the following order:
0001 - Both Condtions Satisfied,
0004 - Condition 1 Satisfied,
0002 - Condition 2 Satisfied,
0003 - No conditions satisfied
At the moment I am doing the following
public TestObj GetNextObj()
{
using (TestDb testDb = new TestDb())
{
TestObj testObj = (from o in testDb.TestTable
where o.Field1 == A && o.Field2 == B
select o).FirstOrDefault();
if (testObj != null)
return testObj;
testObj = (from o in testDb.TestTable
where o.Field1 == A
select o).FirstOrDefault();
if (testObj != null)
return testObj;
testObj = (from o in testDb.TestTable
where o.Field2 == B
select o).FirstOrDefault();
if (testObj != null)
return testObj;
testObj = (from o in testDb.TestTable
select o).FirstOrDefault();
return testObj;
}
}
This works okay, however I want to allow the conditions to be defined in a table and I am worried that when the number of conditions increases that this process will begin taking a very long time.
Is there another way to do what I am attempting here??
Thanks.
EDIT:::::
Now using the following code to select items from a table in order as defined by another table::
public static SortTest GetRow()
{
using (TestDb testDb = new TestDb())
{
SortParam[] sortParams = (from sp in testDb.SortParams
orderby sp.Priority ascending
select sp).ToArray();
if (sortParams.Length == 0)
{
SortTest sortTest = (from st in testDb.SortTests
orderby st.RowId ascending
select st).FirstOrDefault();
Console.WriteLine("Short route");
return sortTest;
}
Console.WriteLine("Long route");
StringBuilder sqlQueryBuilder = new StringBuilder();
sqlQueryBuilder.Append("SELECT * FROM [Proto].[dbo].[SortTests] ORDER BY \n");
foreach (SortParam sortParam in sortParams)
{
sqlQueryBuilder.Append("CASE WHEN " + sortParam.FieldName + " LIKE '%" + sortParam.FieldValue + "%' THEN 1 ELSE 2 END,\n");
}
sqlQueryBuilder.Append("\nRowId"); //By default use row Id
DbSqlQuery<SortTest> dbSqlQuery = testDb.SortTests.SqlQuery(sqlQueryBuilder.ToString());
return dbSqlQuery.FirstOrDefault();
}
}
I may have to alter thigns to prevent Sql Injection, but this works for now.
THANKS!
There's a simple way of doing it in a single query in SQL:
select *
from o
order by case Field1 when 'A' then 1 else 2 end,
case Field2 when 'B' then 1 else 2 end,
RowId

Categories

Resources