1

我有两个不同的表 FirewallLog 和 ProxyLog。这两个表之间没有关系。他们有四个共同的领域:

LogTime ClientIP BytesSent BytesRec

我需要计算一段时间内(如上个月)每天特定 ClientIP 的总使用量,并将其显示如下:

日期 TotalUsage
2/12 125
2/13 145
2/14 0
。.
. .
该 IP 的3/11 150
3/12 125

TotalUsage 为 SUM(FirewallLog.BytesSent + FirewallLog.BytesRec) + SUM(ProxyLog.BytesSent + ProxyLog.BytesRec)。如果那天没有使用(没有记录),我必须显示零。我需要找到解决这个问题的最快方法。有任何想法吗?

4

3 回答 3

3

首先,创建一个日历表。至少有一个id专栏和一个专栏,并在其中填写涵盖您可能感兴趣 calendar_date的每年每一天的日期。(你会发现你会为周末、银行假日和各种其他有用的关于日期的元数据添加标记。)

然后,在将两个表与 UNION 组合后,您可以 LEFT JOIN 到该表。

SELECT
  CALENDAR.calendar_date,
  JOINT_LOG.ClientIP,
  ISNULL(SUM(JOINT_LOG.BytesSent + JOINT_LOG.BytesRec), 0)  AS TotalBytes
FROM
  CALENDAR
LEFT JOIN
(
  SELECT LogTime, ClientIP, BytesSent, BytesRec FROM FirewallLog
  UNION ALL
  SELECT LogTime, ClientIP, BytesSent, BytesRec FROM ProxyLog
)
  AS JOINT_LOG
    ON  JOINT_LOG.LogTime >= CALENDAR.calendar_date
    AND JOINT_LOG.LogTime <  CALENDAR.calendar_date+1
WHERE
      CALENDAR.calendar_date >= @start_date
  AND CALENDAR.calendar_date <  @cease_date
GROUP BY
  CALENDAR.calendar_date,
  JOINT_LOG.ClientIP

SQL Server 非常擅长优化这种类型的 UNION ALL 查询。假设您有适当的索引。

于 2013-07-11T01:34:35.933 回答
2

如果您没有日历表,则可以使用递归 CTE 创建一个:

declare @startdate date = '2013-02-01';
declare @enddate date = '2013-03-01';
with dates as (
      select @startdate as thedate
      union all
      select dateadd(day, 1, thedate)
      from dates
      where thedate < @enddate
     )
select driver.thedate, driver.ClientIP,
       coalesce(fwl.FWBytes, 0) + coalesce(pl.PLBytes, 0) as TotalBytes
from (select d.thedate, fwl.ClientIP
      from dates d cross join
           (select distinct ClientIP from FirewallLog) fwl
     ) driver left outer join
     (select cast(fwl.logtime as date) as thedate,
             SUM(fwl.BytesSent + fwl.BytesRec) as FWBytes
      from FirewallLog fwl
      group by cast(fwl.logtime as date)
     ) fwl
     on driver.thedate = fwl.thedate and driver.clientIP = fwl.ClientIP left outer join
     (select cast(pl.logtime as date) as thedate,
             SUM(pl.BytesSent + pl.BytesRec) as PLBytes
      from ProxyLog pl
      group by cast(pl.logtime as date)
     ) pl
     on driver.thedate = pl.thedate and driver.ClientIP = pl.ClientIP

这使用生成 IP 和日期的所有组合的驱动程序表,然后将其用于加入汇总表。这个公式假设“FirewallLog”包含所有感兴趣的“ClientIp”。

这也打破了这两个值,以防您还想包含它们(例如,查看哪个为总数贡献了更多字节)。

于 2013-07-11T01:43:42.637 回答
1

如果可以的话,我建议创建一个日期查找表。创建表一次,然后您可以根据需要经常使用它。如果没有,您需要考虑创建一个Recursive CTE作为 Dates 表的方法(很简单——查看 stackoverflow 中的示例)。

Select d.date, 
    results.ClientIp
    Sum(results.bytes) 
From YourDateLookupTable d
    Left Join (
        Select ClientIp, logtime, BytesSent + BytesRec bytes From FirewallLog
        Union All
        Select ClientIp, logtime, BytesSent + BytesRec bytes From ProxyLog
    ) results On d.date = results.logtime
Group By d.date, 
    results.ClientIp

这假设 logtime 和 date 数据类型相同。如果 logtime 是日期时间,则需要将其转换为日期。

于 2013-07-11T01:39:14.363 回答