我有两个不同的表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)。如果当天没有使用(没有记录),我必须显示零。
我需要找到解决这个问题的最快方法。任何想法?
答案 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是日期时间,则需要将其转换为日期。