I'll point out some of the problems first:
- There is a mistake in your sample data -
15-60-2015
is not a valid date
- In your attempt the syntax for
MAX
is incorrect - you've used a comma instead of a period. It should be
max(dbo.Replies.replyDate) as [lastreply]
- In your example SQL you have used column
DocumentID
but the table has
docId
- Your expected results do not depend on UserId at all - they are the totals / max date per document type.
The key seems to be that you want to see all document types regardless of whether they appear in the
Replies
table. You can get those as follows
;WITH CTE AS
(
select docid, count(replyid) as num, max(replyDate) as maxDate
from Replies
GROUP BY docid
)
SELECT docName, isnull(num,0), maxDate
FROM Documents D
LEFT OUTER JOIN CTE ON D.docid = CTE.docid
The query above gives your expected results as shown. Note there is no reference to
userId
If, however, what you want is the details for a particular user then introduce
UserId
into the mix as follows
;WITH CTE AS
(
select userid, docid, count(replyid) as num, max(replyDate) as maxDate
from Replies
GROUP BY docid, userid
)
SELECT docName, isnull(num,0), maxDate
FROM Documents D
LEFT OUTER JOIN CTE ON D.docid = CTE.docid
WHERE userid = 1 OR userid is null
Which gives results of
vacation 1 2015-06-14
private 0 NULL
Note the different date.
[EDIT - after OP request for further information]
To get the difference in dates in the format you've suggested is quite simple but can make the SQL look a little messy. I've pulled the messy bit into a 2nd common table expression to (hopefully) make it clear what is going on :
;WITH CTE AS
(
select userid, docid, count(replyid) as num, max(replyDate) as maxDate
from Replies
GROUP BY docid, userid
),
CTE2 AS
(
SELECT CTE.userid, docName, isnull(num,0) as numOfReplies, maxDate
,DateDiff(dd, maxDate, getdate()) As days
, DateDiff(hh, maxDate, getdate()) % 24 As hours
, DateDiff(mi, maxDate, getdate()) % 60 As mins
FROM Documents D
LEFT OUTER JOIN CTE ON D.docid = CTE.docid
)
SELECT CTE2.docName, CTE2.numOfReplies,
Res = '(' + RTRIM((CASE WHEN CTE2.days > 0 THEN CAST(CTE2.days as varchar) + 'd ' END)
+ (CASE WHEN CTE2.hours > 0 THEN CAST(CTE2.hours as varchar) + 'h ' END)
+ (CASE WHEN CTE2.mins > 0 THEN CAST(CTE2.mins as varchar) + 'm' END))
+ ')'
from CTE2
WHERE userid = 1 OR userid is null
By way of explanation - use the DATEDIFF function to work out the number of days since MaxDate and Now. Use the same function modulo 24 to get the remaining number of (whole) hours over and above that number of days, and datediff modulo 60 to get the minutes over and above the number of days and hours. Be aware that time is ticking in that part of the sql - each call to getdate() will return a subtly different value, so don't go down to the millisecond level of comparison!
The final part of the query is just trying to get the output formatted. Under normal circumstances I would do that (i.e. output formatting) in my calling program e.g. probably something like
var res = new StringBuilder("(");
res.Append((days != 0) ? string.Format("{0}d ", days) : "");
res.Append((hours != 0) ? string.Format("{0}h ", hours) : "");
res.Append((mins != 0) ? string.Format("{0}d ", mins) : "");
res.Append(")");
Console.WriteLine(res.ToString().Replace(" )", ")"));