开发者

Complex SQL query

I have a table that tracks emails sent from applications on my server. I would like to write a query that shows how many emails were sent by each application in a certain time period. Here is the table:

---------------------------------------------------------- 
|  emailID  |          SentDT          | ApplicationName | 
---------------------------------------------------------- 
|    1      |  2011-08-04 14:43:31.080 |    Term Form    | 
---------------------------------------------------------- 
|    2      |  2011-08-04 13:59:46.062 |    Term Form    |
---------------------------------------------------------- 
|    3      |  2011-08-03 10:38:15.015 |  Request Form   |
---------------------------------------------------------- 
|    4      |  2011-08-03 05:52:29.005 |    Term Form    |
---------------------------------------------------------- 
|    5      |  2011-08-01 19:58:31.094 | Recruiting Form |  
------------------------------------------------开发者_C百科----------

I would like to see number of emails sent Today, Last 24 hours, Last 7 days, This Month, Last Month, All time.

I know how to do each of these queries by themselves, but I have no clue how to do it in one trip to the database.

For example:

-------------------------------------------------------------- 
|  ApplicationName |  Today | Last24 | Last7days | ThisMonth |
-------------------------------------------------------------- 
|    Term Form     |    2   |   5    |   10      |    19     |
--------------------------------------------------------------
|   Request Form   |    9   |   18   |   36      |    75     |
--------------------------------------------------------------
|  Recruiting Form |    15  |   35   |   100     |    250    |
--------------------------------------------------------------

I tried using a nested select for each subset of times, but I can't use a group by in the nested select. My query that doesn't produce results:

select COUNT(emailID), ApplicationName, (select COUNT(emailID) from emaillog where SentDT > '08/02/2011') as TwoDaysAgo
 from emaillog
 group by ApplicationName
 order by ApplicationName


I think it's much easier to do all the date calculations up front, then you can refer to local variables with logical names instead of embedding all the datediff/case etc. calculations in the query logic.

Made a couple of assumptions here. (1) that no data in EmailLog is in the future (2) that by "Last 7 days" you mean today and the full 6 days preceding. I've also included a grand total - even though it's not listed in your desired output, it seems you were trying to get it with the COUNT() outside the subquery.

DECLARE @now SMALLDATETIME = SYSDATETIME();

DECLARE @today DATE = @now, 
        @24hrsago SMALLDATETIME = DATEADD(DAY, -1, @now);

DECLARE @7daysago DATE = DATEADD(DAY, -6, @today),
        @ThisMonth DATE = DATEADD(DAY, 1-DATEPART(DAY, @today), @today);

--SELECT @now, @today, @24hrsago, @7daysago, @ThisMonth;

WITH d AS
(
    SELECT ApplicationName, c = COUNT(*)
    FROM EmailLog
    GROUP BY ApplicationName
),
g AS
(
    SELECT
        ApplicationName,
        [Today]     = SUM(CASE WHEN SentDt >= @today     THEN 1 ELSE 0 END),
        [Last24]    = SUM(CASE WHEN SentDt >= @24hrsago  THEN 1 ELSE 0 END),
        [Last7Days] = SUM(CASE WHEN SentDt >= @7daysago  THEN 1 ELSE 0 END),
        [ThisMonth] = SUM(CASE WHEN SentDt >= @ThisMonth THEN 1 ELSE 0 END)
    FROM EmailLog
    GROUP BY ApplicationName
)
SELECT d.ApplicationName,
    Total = d.c,
    [Today] = COALESCE(g.[Today], 0),
    [Last24] = COALESCE(g.[Last24], 0),
    [Last7days] = COALESCE(g.Last7days, 0),
    [ThisMonth] = COALESCE(g.ThisMonth, 0)
FROM d LEFT OUTER JOIN g
ON d.ApplicationName = g.ApplicationName;

EDIT

If my assumption was wrong and you don't need the total count by application name, the query becomes much simpler:

DECLARE @now SMALLDATETIME = SYSDATETIME();

DECLARE @today DATE = @now, 
        @24hrsago SMALLDATETIME = DATEADD(DAY, -1, @now);

DECLARE @7daysago DATE = DATEADD(DAY, -6, @today),
        @ThisMonth DATE = DATEADD(DAY, 1-DATEPART(DAY, @today), @today);

SELECT ApplicationName,
    [Today]     = SUM(CASE WHEN SentDt >= @today     THEN 1 ELSE 0 END),
    [Last24]    = SUM(CASE WHEN SentDt >= @24hrsago  THEN 1 ELSE 0 END),
    [Last7Days] = SUM(CASE WHEN SentDt >= @7daysago  THEN 1 ELSE 0 END),
    [ThisMonth] = SUM(CASE WHEN SentDt >= @ThisMonth THEN 1 ELSE 0 END)
FROM EmailLog
GROUP BY ApplicationName;

Ordering optional of course.


try:

   Select ApplicationName, COunt(*) numEmails
   From table
   where SentDT Between @startDateTime and @EndDateTime
   Group By ApplicationName

NOTE: startDateTime and EndDateTime are oundary limits on records to be processed.

if you also want to establish buckets around specified datetiome ranges, you simply need to define those datetime range buckets in another group by expression (and output that same expression in the select clause ... as an example, say the datetime ranges are calendar months...

   Select DateAdd(month, DateDiff(month, 0, SentDT), 0) CalMonth,
       ApplicationName, Count(*) numEmails
   From table
   where SentDT Between @startDateTime and @EndDateTime
   Group By DateAdd(month, DateDiff(month, 0, SentDT), 0), 
            ApplicationName


Something like this should do the trick

select 
    ApplicationName,
    sum(case when daterange = 0 then cnt else 0 end) as Today,
    sum(case when daterange = 1 then cnt else 0 end) as yesterday,
    sum(case when daterange <=2 then cnt else 0 end) as Week,
    sum(case when daterange <=3 then cnt else 0 end) as month,
    sum(cnt) as AllTime
from
    (select 
        ApplicationName, 
        case 
            when days = 0   then '0'
            when days = 1   then '1'
            when days <= 7  then '2'
            when days <= 30 then '3'
            else 4 
        end as
        DateRange, 
        Count(emailid) cnt
    from
        (select ApplicationName, EmailID, datediff(dd, SentDT, getdate()) as Days
        from
            dbo.[YourTableGoesHere]
        ) as foo
    Group by
        ApplicationName,
        case when days < 1 then '0'
            when days = 1 then '1'
            when days <= 7 then '2'
            when days <= 30 then '3'
            else 4 
        end) as bar
group by
    ApplicationName
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜