复杂的SQL查询

时间:2011-08-04 15:52:11

标签: sql sql-server tsql sql-server-2008

我有一个表格,用于跟踪从我服务器上的应用程序发送的电子邮件。我想写一个查询,显示每个应用程序在特定时间段内发送了多少封电子邮件。这是表格:

---------------------------------------------------------- 
|  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 |  
----------------------------------------------------------

我希望看到今天,过去24小时,过去7天,本月,上个月,所有时间发送的电子邮件数量。

我知道如何自己完成这些查询,但我不知道如何在一次数据库中做到这一点。

例如:

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

我尝试对每个子集使用嵌套选择,但我不能在嵌套选择中使用group by。我的查询不会产生结果:

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

3 个答案:

答案 0 :(得分:3)

我认为事先做所有日期计算要容易得多,然后你可以用逻辑名称引用局部变量,而不是在查询逻辑中嵌入所有的约会/案例等计算。

在这里做了几个假设。 (1)未来电子邮件日志中没有数据(2)表示今天和过去6天之前的“过去7天”。我还包括一个总计 - 虽然它没有列在你想要的输出中,但似乎你试图用子查询之外的COUNT()得到它。

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;

编辑

如果我的假设是错误的,并且您不需要应用程序名称的总计数,则查询会变得更加简单:

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;

当然订购可选。

答案 1 :(得分:2)

尝试:

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

注意:startDateTime和EndDateTime是要处理的记录的限制。

如果你还想在指定的日期范围内建立存储桶,你只需要通过表达式在另一个组中定义那些日期时间范围存储桶(并在select子句中输出相同的表达式...作为一个例子,比如日期时间范围是历月...

   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

答案 2 :(得分:1)

这样的事情可以解决问题

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