i am working on an ASP MVC Project and i have a part where i need to export some data to an excel file. the thing is that i need to sum some rows to display a single row. I am not familiar with sql or linq and i am struggling to get the result i want.
there should be 4 columns: requester(string), date(datetime), collection(string), timeinvested(int).
the grouping should be by the column 'collection' (string) as default and if the filter input for requester or date was filled than that would be the next level of grouping. the column 'timespent' should be summarized by the result of the grouping.
example:
requester, date, collection, timeinvested
(1) john, jan 1st, 2019, collection1, 1
(2) mike, jan 1st, 2019, collection1, 3
(3) eric, jan 1st, 2019, collection1, 2
(4) july, jan 1st, 2019, collection2, 5
(5) john, jan 1st, 2012, collection1, 3
here we have 5 rows from the table, once we filter to export only by default (column collection) then rows 1+2+3+5 should sum to 1 row and the 2nd row will be row 4, because the collections are different. like so:
requester, date, collection, timeinvested
(1) john, jan 1st, 2019, collection1, 9
(2) july, jan 1st, 2019, collection2, 5
if i choose to filter also by requester or date then it should apply accordingly.
one big thing here is that there is a private method that checks the date to a particular date and it should export to the file the date year if its after or before the checked date. for example: relative date dec 1st of the same year
if the row date is before relative date then we should write date year - 1;
thanks
var q = (from a in items
select new {
Requester = a.Requester.Name,
Collection = a.Collection.Name,
TimeSpent = a.TimeSpent,
Year = a.Date,
})
.ToList()
.GroupBy(x => new {
x.Requester,
x.Collection,
x.Year,
x.TimeSpent
})
.Select(y => new CollectionModel {
Requester = y.Key.Requester,
Collection = y.Key.Collection,
TimeSpent = y.Sum(z => Convert.ToInt32(z.TimeSpent)),
Year = checkDate(y.Key.Year),
});
return q.ToList();
this is how i made it work:
var q = (from a in items
select new {
Requester = a.Requester.Name,
Collection = a.Collection.Name,
TimeSpent = a.TimeSpent,
Year = a.Date,
})
.Where(Where(a => dt == null || (dt != null && a.Year == dt.Year))
.ToList()
.GroupBy(x => new {
x.Requester,
x.Collection,
x.Year,
})
.Select(y => new CollectionModel {
Requester = y.Key.Requester,
Collection = y.Key.Collection,
TimeSpent = y.Sum(z => Convert.ToInt32(z.TimeSpent)),
Year = checkDate(y.Key.Year),
});
return q.ToList();
First, remove the "x.TimeSpent" from your GroupBy, you need to aggregate that variable, not group by it. secondly, could you post the output as well?
Related
I want to count the amount of records by year, for each year. These records contain a datecreated field. But the count should include the previous years as well. So counting the years of 2013 should, include those lower years as well, but not yet of 2014 and higher.
Explanation preferably in linq.
(sql is totally fine though)
I tried doing this by grouping by year, and then count for each year. Now only the previous years should be added, for each year.
I know this can be done with a lot where statements and selecting the results, but there should be a better way.
In SQL you need SUM OVER but it is not supported by Linq. You can download yearly data and calculate the cumulative sums in memory.
var fromYear = 2010;
var toYear = 2019;
var yearlyData = Receipts.Where(x => x.DateCreated.Year >= fromYear & x.DateCreated.Year <= toYear)
.GroupBy(x => x.DateCreated.Year)
.Select(x => new { Year = x.Key, Count = x.Count() })
.ToList();
var result = Enumerable.Range(fromYear, toYear - fromYear)
.Select(year => new
{
Year = year,
CumulativeCount = yearlyData.Where(y => y.Year <= year).Sum(y => y.Count)
});
Also you can use an outer variable:
var fromYear = 2010;
var toYear = 2019;
var yearlyData = Receipts.Where(x => x.DateCreated.Year >= fromYear & x.DateCreated.Year <= toYear)
.GroupBy(x => x.DateCreated.Year)
.Select(x => new { Year = x.Key, Count = x.Count() })
.OrderBy(x => x.Year)
.ToList()
;
var sum = 0;
var result = yearlyData.Select(x => new {x.Year, CumulativeSum = sum += x.Count});
select sum(case when year(datecreated) <= 2013 then 1 else 0 end) as until_2013,
sum(case when year(datecreated) <= 2014 then 1 else 0 end) as until_2014,
sum(case when year(datecreated) <= 2015 then 1 else 0 end) as until_2015
from your_table
Here's your query.
select count(1), year(created_date) from tableA
where year(created_date) < 2014
group by year(created_date)
I have a SQL Server query like this:
select
month(fact_date) as month,
sum(case when beef_dairy_stat = 1 and param_id = 1 then 1 else 0 end) as cnt
from
user_behave_fact
where
YEAR(fact_date) = 2018
group by
month(fact_date)
order by
month
with a result of
month cnt
------------
1 10
2 20
Now I need to convert this query to its corresponding Entity Framework query.
This is my current attempt:
var sql_rez_ICC = new List<Tuple<int, int>>();
sql_rez_ICC = db.user_behave_fact
.Where(x => x.fact_date.Value.Year == selected_year)
.GroupBy(y => y.fact_date.Value.Month)
.Select(y =>new { month = y.Select(x=>x.fact_date.Value.Month), icc_count = y.Count(x => x.beef_dairy_stat == true && x.param_id == 1) })
.AsEnumerable()
.Select(y => new Tuple<int, int>(y.month, y.icc_count))
.ToList();
However on second .Select, I get an error on month which is
Cannot convert from System.Collection.Generic.IEnumrable to int
y.Select(x=>x.fact_date.Value.Month) returns an IEnumerable<int>. Use y.Key instead.
I'm using node.js to connect to an SQL database (SQL Server 2016 specifically). My table, called transactionCounts, has the following tables and data types:
staff_id: varchar(50), date: Date, count: int;
The 'date' field is just a date, not a DateTime, for clarity. Records look like this: "2017-08-07"
I'm using the mssql package, const sql = require('mssql');
So basically, I have a function which accepts a start date and an end date and does this with them:
function(start, end) {
let ps = new sql.PreparedStatement(transactionRegisterSqlPool);
ps.input('start', sql.Date);
ps.input('end', sql.Date);
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
.execute({start: start, end: end}, (err, result) => {});
});
};
I've simplified the function for illustrations sake (it normally returns a promise), but here's what's going wrong:
I pass in the dates of Aug 20 midnight, and Aug 27 midnight, and what I'm expecting to get back is the sum for the dates 20,21,22,23,24,25 and 26 naturally (7 days, a week).
26th isn't being included though (definitely), and I'm not entirely sure but I'd wager that the 19th is being included. I think it's a daylight-savings issue, because these dates, when i call .toISOString(), look like 2017-08-19T23:00:00.000Z and 2017-08-26T23:00:00.000Z respectively (11pm the night prior).
I've modified my function to use strings instead of dates, and this seems to work and returns the correct Sums:
function(start, end) {
let ps = new sql.PreparedStatement(transactionRegisterSqlPool);
ps.input('start', sql.VarChar);
ps.input('end', sql.VarChar);
start = `${start.getFullYear()}/${start.getMonth() + 1}/${start.getDate()}`;
end = `${end.getFullYear()}/${end.getMonth() + 1}/${end.getDate()}`;
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
ps.execute({start: start, end: end}, (err, result) => {});
});
};
But it seems...wrong to take my dates and turn them into strings to work my way around this issue. What is the correct way to deal with dates between Javascript Dates and SQL Dates, so that this apparent Daylight-Savings-caused issue is avoided?
Your problem is that JavaScript does not have a "date" type, only "datetime", yet SQL does have a "date" type. Because of that, you will have to do the conversion.
If you wrap it in a function, it is still readable:
function toDateString(d) {
return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
}
ps.prepare('SELECT staff_id, SUM(Count) TotalCount FROM [TransactionRegister].[dbo].[transactionCounts] ' +
'WHERE date >= #start AND date < #end GROUP BY staff_id', err => {
ps.execute({start: toDateString(start), end: toDateString(end)}, (err, result) => {});
});
I am trying to get these querys to return a hash that has id's like this:
{[08/14/2015, [... records ...]],[08/15/2015, [... records ...]]}
With the following code it does this:
#trucks = Truck.where(:company_id => 33)
#trucks_by_date = #trucks.group_by(&:available)
=> {[Fri, 14 Aug 2015 00:00:00 UTC +00:00, [... records ...]], [Sat, 15 Aug 2015 00:00:00 UTC +00:00, [... records ...]]}
I have tried this but it errors:
#trucks.group_by("CAST(available AS DATE)")
--- AND ---
#trucks.group("DATE(available)")
=> 1.9.3-p551 :074 > #trucks_by_date = #trucks.group("DATE(available)")
Truck Load (74.2ms) SELECT "trucks".* FROM "trucks" WHERE "trucks"."company_id" = 33 GROUP BY DATE(available)
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "trucks.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "trucks".* FROM "trucks" WHERE "trucks"."company_id"...
^
: SELECT "trucks".* FROM "trucks" WHERE "trucks"."company_id" = 33 GROUP BY DATE(available)
from /usr/local/rvm/gems/ruby-1.9.3-p551#loadmax/gems/activerecord-3.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `async_exec'
from /usr/local/rvm/gems/ruby-1.9.3-p551#loadmax/gems/activerecord-3.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `exec_no_cache'
from /usr/local/rvm/gems/ruby-1.9.3-p551#loadmax/gems/activerecord-3.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:663:in `block in exec_query'
If i do this: (also wrong format for date)
#trucks_by_date = #trucks.group("DATE(available)").count
=> `{"2015-08-13"=>5, "2015-07-27"=>3, "2015-08-18"=>2, "2015-08-14"=>6, "2015-08-17"=>1, "2015-07-31"=>2, "2015-08-12"=>5, "2015-08-11"=>8, "2015-07-30"=>4, "2015-08-10"=>13, "2015-08-07"=>4, "2015-08-03"=>4, "2015-07-24"=>1, "2015-07-28"=>5}`
But i don't want counts i want complete records.
REASON: I have a initializer that changes formats on data like so:
Date::DATE_FORMATS[:default] = "%m/%d/%Y"
Time::DATE_FORMATS[:default] = "%m/%d/%Y"
and when i try to iterate thru the hash it changes the formats so it cant find the right position of the hash
#trucks = Truck.where(:company_id => 33)
#trucks_by_date = #trucks.group_by {|t| t.available.to_s(:default) }
I want to make a simple Blog Post Archive List like below
2014
January (1)
2013
December (1)
November (14) -> Link to search with date
October (3)
May (5)
April (3)
I need to send this via ViewBag.Archives. When I perform below SQL in SQL Server Management Studio.
select year(Created) as PostYear, datename(month,Created) as PostMonth,count(ID) as ArticleAmount from Post group by year(Created), datename(MONTH,Created) order by PostYear, PostMonth
I get:
PostYear PostMonth ArticleAmount
2010 February 1
2011 September 1
2012 April 1
2012 February 1
2013 February 4
2013 March 1
2014 February 1
My Code:
ViewBag.Archives = db.Posts
.GroupBy(group => new { group.Created.Year, group.Created.Month })
.Select(x => new { count = x.Count(), Year = x.Key.Year, Month = x.Key.Month });
My View:
#foreach (var item in ViewBag.Archives)
{
<p>#item.Year</p>
}
ERROR: Additional information: 'object' does not contain a definition for 'Year'
Thank you
Are you looking for something like:
ViewBag.Archives = db.Posts
.GroupBy(group => new {group.Created.Year, group.Created.Month})
.Take(5)
.Select(x => new GuestBookPost()
{
count = x.Count,
Year = x.Key.Created.Year,
Month = x.Key.Created.Month
}).ToList();
EDIT
Use the ToList() on the select :).
Try using an object or a model to store the data in, this will also make is easier to add month names as accessing in the view. Example below, replaced "ObjectName()", with "PostGroup":
public class GuestbookPost {
public int Count { get; set; }
public int Year { get; set; }
public int Month { get; set; }
}
PS: Sorry for the bad formatting, still learning :)