总结两个不同表中的列

时间:2013-07-11 01:27:13

标签: sql sql-server

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

LogTime ClientIP BytesSent BytesRec

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

日期总用量
2/12 125
2/13 145
2/14 0
。 。
。 。
3/11 150
3/12 125

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

3 个答案:

答案 0 :(得分:3)

首先,创建一个Calendar表。一个至少有一个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查询。假设你有适当的索引。

答案 1 :(得分: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”。

这也会打破这两个值,以防你想要包含它们(例如,看看哪个值占总数的更多字节)。

答案 2 :(得分:1)

如果这是一个选项,我建议创建一个Dates Lookup表。创建一次表,然后您可以根据需要经常使用它。如果没有,你需要考虑创建一个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是日期时间,则需要将其转换为日期。