Aging - Calendar and Business Days Different Records of Data - sql

I am currently using SQL Server 2012 and I have an aging question. I tried to include some sample data below with 4 records.
FileNumber FileType CompletedDate
90440 Internal 8/11/2017
90440 Strategy NULL
90441 Internal 8/10/2017
90441 Strategy NULL
A Strategies' aging is calculated from the Internal FileType's Completed Date all the way up to the Strategy FileType's Completed Date. Every FileNumber can have multiple FileTypes associated with it. If the Strategy's Completed Date is NULL, then it would be from Internal FileType's Completed Date all the way up to today's date or GETDATE().
So I'm trying to show Count of Pending Strategies and their current aging in Business and Calendar Days...so essentially I would want the data to return like this.
File Number FileType AgeBusiness AgeCalendar
90440 Strategy 2 4
90441 Strategy 3 5
Any clue on how I would go about this? Any help is appreciated.

Something like this may work but I'm not 100% sure since it depends on what sort of Filetypes are in the table, whether you are accounting for holidays, what happens when Strategy (or whatever is the latest file type) has a value for completed date.
;WITH Internal AS
(
select FileNumber, FileType,
DATEDIFF(day,CompletedDate,getdate())- (datediff(wk, CompletedDate, getdate()) * 2) -
case when datepart(dw, CompletedDate) = 1 then 1 else 0 end +
case when datepart(dw, getdate()) = 1 then 1 else 0 end as AgeBusiness,
DATEDIFF(day,CompletedDate,getdate()) as AgeCalendar
from #test
where FileType = 'Internal'
)
select t.FileNumber, t.FileType, i.AgeBusiness, i.AgeCalendar
from #test t
inner join Internal i on
(t.FileNumber = i.FileNumber)
where CompletedDate is null
the problem with the above is it wouldn't show a row if Strategy (or whatever is the latest file type) HAS a completed date. Therefore you may want something like
;WITH Internal AS
(
select FileNumber, FileType,
DATEDIFF(day,CompletedDate,getdate())- (datediff(wk, CompletedDate, getdate()) * 2) -
case when datepart(dw, CompletedDate) = 1 then 1 else 0 end +
case when datepart(dw, getdate()) = 1 then 1 else 0 end as AgeBusiness,
DATEDIFF(day,CompletedDate,getdate()) as AgeCalendar
from #test
where FileType = 'Internal'
), Latest AS
(
select FileNumber, FileType, RANK() OVER
(PARTITION BY FileNumber ORDER BY COALESCE(CompletedDate,GETDATE()) DESC) AS rnk
from #test
)
select l.FileNumber, l.FileType, i.AgeBusiness, i.AgeCalendar
from Latest l
inner join Internal i on
(l.FileNumber = i.FileNumber)
where rnk = 1
where it would show the row regardless of if it's null or not, but at the expense of adding a RANK() which is more intensive.

You don't need a CTE but I included it to make it more readable.
WITH DateRanges AS (
SELECT yt.FileNumber
,yt.FileType
,SELECT TOP 1 CompletedDate FROM YourTable WHERE yt.FileNumber = FileNumber AND FileType = 'Internal' AS InternalCompletedDate
,CASE WHEN yt.CompletedDate IS NULL THEN CAST(GETDATE() AS DATE) ELSE yt.CompletedDate END AS StrategyCompletedDate -- I forgot the NULL part too...
FROM YourTable yt
WHERE yt.FileType = 'Strategy'
)
SELECT FileNumber
,FileType
,(DATEDIFF(dd,InternalCompletedDate, StrategyCompletedDate) + 1)
-(DATEDIFF(wk, InternalCompletedDate, StrategyCompletedDate) * 2)
-(CASE WHEN DATENAME(dw, InternalCompletedDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, StrategyCompletedDate) = 'Saturday' THEN 1 ELSE 0 END) AS AgeBusiness
,DATEDIFF(dd, InternalCompletedDate, StrategyCompletedDate) AS AgeCalendar
FROM DateRanges
Edit: Should be good now. I rushed it a bit.

Related

SqlServer : Number of 'open' issues on a daily basis

I'm getting an error with this query "Msg 102, Level 15, State 1, Line 12
Incorrect syntax near ';'" and have been at it for a few hours now. I'm trying to calculate 'open' issues on given days (ideally between a timeframe but for now just on dates that have entries).
My Data is simplified as:
IssueID, CreationDate, CompletionDate
I'd like to tally open issues which is when Year(CompletionDate)=1900 and they are cumulative while they are open, ie: if yesterday there was 1 issue open and today has 1 issue open as well, then today's count of open is 2. They should drop off once they are resolved (Year(CompletionDate) <> 1900). Please help I think i'm close?
SELECT
x.created_date,
aOpen + Open_Issue - Resolved_Issue as totopen
from(
select
convert(varchar(10), cast(i.CreationDate as date), 101) as created_date,
sum( case when YEAR(i.CompletionDate)='1900' then 1 else 0 end) as aOpen,
sum( case when YEAR(i.CompletionDate)<>'1900' AND (i.CompletionDate >=
i.CreationDate) then 1 else 0 end ) as Open_Issue,
coalesce(tot,0) as Resolved_Issue
FROM Issues i
LEFT JOIN (SELECT count(IssueID) as tot, CompletionDate as resolved
from Issues where YEAR(CompletionDate)<>'1900' group by CompletionDate,
count(IssueID))x
ON i.CreationDate = x.resolved);
UPDATE
I have this returning output correctly on a daily basis only, as in it is not accounting for previous, still open issues (Legacy_Open_Issue) and adding them.
SELECT
created_date,
aOpen_Today + Legacy_Open_Issue - Resolved_Issue as totopen
FROM(
SELECT
convert(varchar(10), cast(i.CreationDate as date), 101) as created_date,
sum( case when YEAR(i.CompletionDate)=1900 then 1 else 0 end) as aOpen_Today,
sum( case when (YEAR(i.CompletionDate)<>1900 AND (i.CompletionDate >= i.CreationDate)) then 1 else 0 end ) as Legacy_Open_Issue,
coalesce(tot,0) as Resolved_Issue
FROM Issues i
LEFT JOIN (
SELECT count(IssueID) as tot, CompletionDate as resolved
FROM Issues
WHERE YEAR(CompletionDate)<>1900 group by CompletionDate
)x ON x.resolved = i.CreationDate
GROUP BY convert(varchar(10), cast(i.CreationDate as date), 101), coalesce(tot,0)
) AS y;
My Data is
IssueID CreationDate CompletionDate
1 1/15/2019 1/1/1900
2 1/16/2019 1/17/2019
3 1/16/2019 1/1/1900
4 1/20/2019 1/21/2019
5 1/28/2019 1/1/1900
6 1/30/2019 1/1/1900
My Output is
created_date totopen
1/15/2019 1
1/16/2019 2
1/20/2019 1
1/28/2019 1
1/30/2019 1
My Output SHOULD be
created_date totopen
1/15/2019 1
1/16/2019 3
1/20/2019 3
1/28/2019 3
1/30/2019 4
thank you for your help
You need to alias the derived table such as:
SELECT
x.created_date,
aOpen + Open_Issue - Resolved_Issue as totopen
from(
select
convert(varchar(10), cast(i.CreationDate as date), 101) as created_date,
sum( case when YEAR(i.CompletionDate)='1900' then 1 else 0 end) as aOpen,
sum( case when YEAR(i.CompletionDate)<>'1900' AND (i.CompletionDate >=
i.CreationDate) then 1 else 0 end ) as Open_Issue,
coalesce(tot,0) as Resolved_Issue
FROM Issues i
LEFT JOIN (SELECT count(IssueID) as tot, CompletionDate as resolved
from Issues where YEAR(CompletionDate)<>'1900' group by CompletionDate,
count(IssueID))x
ON i.CreationDate = x.resolved) as DT;
Derived tables require an alias. You need to add "AS {alias}" to the end of your query. You should also format and line break the code for better legibility.
SELECT
x.created_date,
aOpen + Open_Issue - Resolved_Issue as totopen
from(
select
convert(varchar(10), cast(i.CreationDate as date), 101) as created_date,
sum( case when YEAR(i.CompletionDate)=1900 then 1 else 0 end) as aOpen,
sum( case when YEAR(i.CompletionDate)<>1900 AND (i.CompletionDate >= i.CreationDate) then 1 else 0 end ) as Open_Issue,
coalesce(tot,0) as Resolved_Issue
FROM Issues i
LEFT JOIN (
SELECT count(IssueID) as tot, CompletionDate as resolved
from Issues
where YEAR(CompletionDate)<>1900
group by CompletionDate
)x ON i.CreationDate = x.resolved
group by convert(varchar(10), cast(i.CreationDate as date), 101)
) AS y;
Also, SO generally doesn't do multiple questions per post. I addressed the error/alias issue, but if you have results issues, you should post a new question with sample data and expected results.
To be able to use date ranges and ensure there are no gaps in your output (ie. on dates where no tickets were created), you may want to consider using a Dates fact / reference table like this:
Select d.Date
, count(i.IssueID) as TotalOpen
, sum(case when DateDiff(DD, d.Date, cast(i.CreationDate as date)) = 0 then 1 else 0 end) as NewOpened
, sum(case when DateDiff(DD, d.Date, cast(i.CompletionDate as date)) = 0 then 1 else 0 end) as NewClosed
From Dates d
Left join Issues i
on d.Date between convert(varchar(10), cast(i.CreationDate as date), 101) and
case when YEAR(i.CompletionDate)='1900' then d.Date else i.CompletionDate end
Group by d.Date
Fill the Dates table with all the dates you'd want to display results for (ie. everyday, weekdays) or use a where clause to filter the date range / pattern.

CASE in WHERE Clause

Below is my current SQL Server 2012 query. Basically I want the information from the last business day, but on Monday, I want it to pull Friday's info instead of Sunday. This is what I have so far in my query but it won't accept it.
USE [LetterGeneration]
SELECT
g.LetterGenerationPrintJobId,
CONVERT(CHAR(12), r.CreatedDate, 101) AS CreatedDate,
YEAR(r.CreatedDate) AS Year,
MONTH(r.CreatedDate) AS Month,
DAY(r.CreatedDate) AS Day,
CASE
WHEN DATEPART(dw, r.CreatedDate) = 1
THEN 1
WHEN DATEPART(dw, r.CreatedDate) = 7
THEN 1
ElSE 0
END AS Weekend,
s.LetterGenerationStatusId AS Status,
COUNT(g.LetterGenerationId) AS LetterCount,
SUM(g.LetterPageCount) AS PageCount,
t.IsLitigationCoverLetterAllowed,
CASE
WHEN g.CarrierTrackingNumber LIKE '%1ZE%'
THEN 1
WHEN g.CarrierTrackingNumber LIKE '921489%'
THEN 2
WHEN g.CarrierTrackingNumber LIKE '917190%'
THEN 2
ELSE 3
END AS CarrierType
FROM
[LetterGenerationTemplateRequest] AS R
INNER JOIN
[LetterGenerationTemplate] AS T ON t.[LetterGenerationTemplateId] = r.LetterGenerationTemplateId
INNER JOIN
LetterGeneration G ON g.LetterGenerationTemplateRequestId = r.LetterGenerationTemplateRequestId
INNER JOIN
LetterGenerationStatus S ON g.LetterGenerationStatusId = s.LetterGenerationStatusId
WHERE
(CASE
WHEN (DATENAME(dw,GETDATE()) = 'Monday')
THEN (DATEDIFF(d, r.CreatedDate, GETDATE()) = 3)
ELSE (DATEDIFF(d, r.CreatedDate, GETDATE()) = 1)
END)
AND t.[TemplateKey] NOT LIKE '%PLTV1%'
AND s.LetterGenerationStatusId = 19
ORDER BY
r.CreatedDate DESC, g.LetterGenerationPrintJobId DESC
What am I missing or misunderstanding about my WHERE clause in order to make it work in the way I'm thinking?
Thanks
Maybe convert to a regular AND/OR?
WHERE (
((DATENAME(dw,GETDATE()) = 'Monday') AND (DATEDIFF(d, r.CreatedDate, GETDATE()) = 3))
OR
(DATEDIFF(d, r.CreatedDate, GETDATE()) = 1)
)
....
What am I missing or misunderstanding about my WHERE clause in order to make it work in the way I'm thinking?
Though you haven't given the error message you're getting, I'm sure it's syntax related because you're putting the test INSIDE the result of the case, not outside it
You're writing:
WHERE CASE WHEN it_is_monday THEN data_date = friday ELSE data_date = yesterday END
You should be writing:
WHERE data_date = CASE WHEN it_is_monday THEN friday ELSE yesterday END
Essentially: you're not supposed to use case/when in a where clause to do your "column = something" comparison and return you true or false, you're supposed to use it to just return the "something" you compare against "column" else in order to get your true or false
The other answers focus on "giving you a working solution"; this answer focuses on telling you what was going wrong with your thought processes re your original query
Here's a simpler example:
--wrong syntax to search a table full of cats (4 legs) and people (2 legs)
WHERE CASE WHEN animal_type = 'cat' THEN legs = 4 ELSE legs = 2 END
--right syntax
WHERE limbs = CASE WHEN animal_type = 'cat' THEN 4 ELSE 2 END
Ignoring holidays for a second, and assuming you have at least one record for every date, something like this should work.
where cast(createdDate as date) =
(select max(createdDate )
from table
where createdDate < cast(getDate() as date
and dateName(dw, createdDate in ('Monday' etc)
)
In order to maintain SARGability(able to do a seek against an index) you want to make sure the table columns in the predicate aren't included in any functions.
The following should work and maintain SARGability...
WHERE
r.CreatedDate = CASE
WHEN DATEPART(dw, getdate) = 2
THEN DATEADD(dd, -3, CAST(GETDATE() AS DATE))
ELSE CAST(GETDATE() AS DATE)
END
HTH,
Jason

How to group filtered rows against non filtered by month

I am trying to generate a report for accepted orders each month against the total orders for that month. For example, I have a table Orders like so:
Order_Id Submit_Date Order_Status
-------- ----------- ------------
1 20130501 Accepted
2 20130509 Rejected
3 20130610 Accepted
4 20130614 Accepted
5 20130626 Rejected
6 20130802 Accepted
7 20130801 Accepted
8 20131014 Accepted
9 20140116 Rejected
10 20140121 Rejected
And would like to get the results like so:
[Month] Accepted Total
------- -------- -----
2013-05 1 2
2013-06 2 3
2013-08 2 2
2013-10 1 1
2014-01 2 2
How do I go about it?
Assuming you will never have a time component, this should work just fine:
DECLARE #d TABLE([Order] INT, [Date] DATETIME, [Status] CHAR(8));
INSERT #d VALUES
(1 ,'20130501','Accepted'),
(2 ,'20130509','Rejected'),
(3 ,'20130610','Accepted'),
(4 ,'20130614','Accepted'),
(5 ,'20130626','Rejected'),
(6 ,'20130802','Accepted'),
(7 ,'20130801','Accepted'),
(8 ,'20131014','Accepted'),
(9 ,'20140116','Rejected'),
(10,'20140121','Rejected');
SELECT
[Month] = DATEADD(DAY, 1-DAY([Date]), [Date]),
Accepted = SUM(CASE WHEN [Status] = 'Accepted' THEN 1 ELSE 0 END),
COUNT(*)
FROM #d
GROUP BY DATEADD(DAY, 1-DAY([Date]), [Date])
ORDER BY [Month];
(And if you are on SQL Server 2008 or newer, you should use the DATE data type to prevent having to deal with any errant hours/minutes.)
If you can have hours/minutes sometimes, and you're not on 2008 or greater, then:
SELECT
[Month] = DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0),
Accepted = SUM(CASE WHEN [Status] = 'Accepted' THEN 1 ELSE 0 END),
COUNT(*)
FROM #d
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)
ORDER BY [Month];
I strongly recommend avoiding any solutions that group by using string conversions. Date/time math is much more efficient in SQL Server than converting to strings. Also if you want the client side to present things like 2013-05, use Format(), ToString() etc. to apply that string formatting on the client.
To get yyyy-dd format you can use this
SELECT CONVERT(VARCHAR(7),[Date],20)
,COUNT(CASE WHEN [status] = 'Accepted' THEN 1
ELSE NULL END) AS 'Accepted'
,COUNT(*) AS Total
FROM Orders
GROUP BY CONVERT(VARCHAR(7),[Date],20)
Try it:
SELECT
CONVERT(VARCHAR(4), YEAR(Date)) + '-' + CONVERT(VARCHAR(2), MONTH(Date)) Period,
SUM(CASE WHEN Status = 'Accepted' THEN 1 ELSE 0) Accepted,
COUNT(*) Total
FROM Orders
GROUP BY YEAR(Date), MONTH(Date)
ORDER BY YEAR(Date), MONTH(Date)

multi-select sql query with date range

I have this query where I get totals of different stats from an employee roster table.
SELECT A.rempid AS EmpId,
E.flname,
A.rdo_total,
B.grave_total,
C.sundays,
D.holidays
FROM (SELECT rempid,
Count(rshiftid)AS RDO_Total
FROM rtmp1
WHERE rshiftid = 2
GROUP BY rempid
HAVING Count(rshiftid) > 0) A,
(SELECT rempid,
Count(rshiftid)AS Grave_Total
FROM rtmp1
WHERE rshiftid = 6
GROUP BY rempid
HAVING Count(rshiftid) > 0)B,
(SELECT rempid,
Count(rshiftid) AS Sundays
FROM rtmp1
WHERE Datepart(dw, rdate) = 1
AND rshiftid > 2
GROUP BY rempid
HAVING Count(rshiftid) > 0)C,
(SELECT rempid,
Count(rshiftid) AS Holidays
FROM rtmp1
WHERE rdate IN (SELECT pubhdt
FROM pubhol)
AND rshiftid > 2
GROUP BY rempid
HAVING Count(rshiftid) > 0)D,
(SELECT empid,
[fname] + ' ' + [sname] AS flName
FROM remp1)E
WHERE A.rempid = B.rempid
AND A.rempid = E.empid
AND A.rempid = C.rempid
AND A.rempid = D.rempid
ORDER BY A.rempid
I would like to add a date range into it, so that I can query the database within 2 dates. The rTmp1 table has a column called rDate. I was wondering what the best way to do this. I could add it to a stored procedure and add variable to each select query. Or is there a better way to run the query within a date range.
i think just add an additional where clause item similar to:
AND ( rDate > somedate AND rDate < someotherdate )
Adding the date range to each query is the most direct solution.
Making it a stored procedure is something that can always be done with a query, but has nothing to do with this specific case.
If the number of records resulting from narrowing down your table to the specified date range is substantially less than the entire table, it might be an option to insert these records into a temporary table or a table variable and run your existing query on that table/resultset.
Though I do not have any data to test, you might consider the following query as it is more easy to read and might perform better. But you have to check the results for yourself and maybe do some adjustments.
DECLARE #startDate date = '12/01/2012'
DECLARE #endDate date = DATEADD(MONTH, 1, #startDate)
SELECT
[e].[empid],
[e].[fname] + ' ' + [e].[sname] AS [flName],
SUM(CASE WHEN [t].[rshiftid] = 2 THEN 1 ELSE 0 END) AS [RDO_Total],
SUM(CASE WHEN [t].[rshiftid] = 6 THEN 1 ELSE 0 END) AS [Grave_Total],
SUM(CASE WHEN [t].[rshiftid] > 2 AND DATEPART(dw, [t].[rdate]) = 1 THEN 1 ELSE 0 END) AS [Sundays],
SUM(CASE WHEN [t].[rshiftid] > 2 AND [h].[pubhdt] IS NOT NULL THEN 1 ELSE 0 END) AS [Holidays]
FROM [remp1] [e]
INNER JOIN [rtmp1] [t] ON [e].[empid] = [t].[rempid]
LEFT JOIN [pubhol] [h] ON [t].[rdate] = [h].[pubhdt]
WHERE [t].[rdate] BETWEEN #startDate AND #endDate
GROUP BY
[e].[empid],
[e].[fname],
[e].[sname]
ORDER BY [empid] ASC

SQL statement to get record datetime field value as column of result

I have the following two tables
activity(activity_id, title, description, group_id)
statistic(statistic_id, activity_id, date, user_id, result)
group_id and user_id come from active directory. Result is an integer.
Given a user_id and a date range of 6 days (Mon - Sat) which I've calculated on the business logic side, and the fact that some of the dates in the date range may not have a statistic result for the particular date (ie. day1 and day 4 may have entered statistic rows for a particular activity, but there may not be any entries for days 2, 3, 5 and 6) how can I get a SQL result with the following format? Keep in mind that if a particular activity doesn't have a record for the particular date in the statistics table, then that day should return 0 in the SQL result.
activity_id group_id day1result day2result day3result day4result day5result day6 result
----------- -------- ---------- ---------- ---------- ---------- ---------- -----------
sample1 Secured 0 5 1 0 2 1
sample2 Unsecured 1 0 0 4 3 2
Note: Currently I am planning on handling this in the business logic, but that would require multiple queries (one to create a list of distinct activities for that user for the date range, and one for each activity looping through each date for a result or lack of result, to populate the 2nd dimension of the array with date-related results). That could end up with 50+ queries for each user per date range, which seems like overkill to me.
I got this working for 4 days and I can get it working for all 6 days, but it seems like overkill. Is there a way to simplify this?:
SELECT d1d2.activity_id, ISNULL(d1d2.result1,0) AS day1, ISNULL(d1d2.result2,0) AS day2, ISNULL(d3d4.result3,0) AS day3, ISNULL(d3d4.result4,0) AS day4
FROM
(SELECT ISNULL(d1.activity_id,0) AS activity_id, ISNULL(result1,0) AS result1, ISNULL(result2,0) AS result2
FROM
(SELECT ISNULL(statistic_result,0) AS result1, ISNULL(activity_id,0) AS activity_id
FROM statistic
WHERE user_id='jeremiah' AND statistic_date='11/22/2011'
) d1
FROM JOIN
(SELECT ISNULL(statistic_result,0) AS result2, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/23/2011'
) d2
ON d1.activity_id=d2.activity_id
) d1d2
FULL JOIN
(SELECT d3.activity_id AS activity_id, ISNULL(d3.result3,0) AS result3, ISNULL(d4.result4,0) AS result4
FROM
(SELECT ISNULL(statistic_result,0) AS result3, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/24/2011'
) d3
FULL JOIN
(SELECT ISNULL(statistic_result,0) AS result4, ISNULL(activity_id,0) AS activity_id
FROM statistic WHERE user_id='jeremiah' AND statistic_date='11/25/2011'
) d4
ON d3.activity_id=d4.activity_id
) d3d4
ON d1d2.activity_id=d3d4.activity_id
ORDER BY d1d2.activity_id
Here is a typical approach for this kind of thing:
DECLARE #minDate DATETIME,
#maxdate DATETIME,
#userID VARCHAR(200)
SELECT #minDate = '2011-11-15 00:00:00',
#maxDate = '2011-11-22 23:59:59',
#userID = 'jeremiah'
SELECT A.activity_id, A.group_id,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 0 THEN S.Result ELSE 0 END) AS Day1Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 1 THEN S.Result ELSE 0 END) AS Day2Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 2 THEN S.Result ELSE 0 END) AS Day3Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 3 THEN S.Result ELSE 0 END) AS Day4Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 4 THEN S.Result ELSE 0 END) AS Day5Result,
SUM(CASE WHEN DATEDIFF(day, #minDate, S.date) = 5 THEN S.Result ELSE 0 END) AS Day6Result
FROM activity A
LEFT OUTER JOIN statistic S
ON A.activity_id = S.activity_ID
AND S.user_id = #userID
WHERE S.date between #minDate AND #maxDate
GROUP BY A.activity_id, A.group_id
First, I'm using group by to reduce the resultset to one row per activity_id/group_id, then I'm using CASE to separate values for each individual column. In this case I'm looking at which day in the last seven, but you can use whatever logic there to determine what date. The case statements will return the value of S.result if the row is for that particular day, or 0 if it's not. SUM will add up the individual values (or just the one, if there is only one) and consolidate that into a single row.
You'll also note my date range is based on midnight on the first day in the range and 11:59PM on the last day of the range to ensure all times are included in the range.
Finally, I'm performing a left join so you will always have a 0 in your columns, even if there are no statistics.
I'm not entirely sure how your results are segregated by group in addition to activity (unless group is a higher level construct), but here is the approach I would take:
SELECT activity_id
day1result = SUM(CASE DATEPART(weekday, date) WHEN 1 THEN result ELSE 0 END)
FROM statistic
GROUP BY activity_id
I will leave the rest of the days and addition of group_id to you, but you should see the general approach.