【问题标题】:Summing up columns from two different tables总结来自两个不同表的列
【发布时间】:2013-07-11 01:27:13
【问题描述】:

我有两个不同的表 FirewallLog 和 ProxyLog。这两个表之间没有关系。它们有四个共同的字段:

LogTime     ClientIP     BytesSent     BytesRec

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

日期       TotalUsage
2/12         125
2/13         145
2/14         0
. .
. .
3/11         150
3/12         125

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

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

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

    【讨论】:

      【解决方案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”。

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

      【讨论】:

      • 虽然示例数据中没有显示,但 OP 确实声明了 for that IP,这暗示我 ClientIP 字段也需要在 GROUP BY 中。 (哦,现在我也读到了I need to Calculate the total usage of a particular ClientIP。)
      • ProxyLog中存在ClientIP但FirewallLog中不存在怎么办?由于一些奇怪的深奥原因,涉及我迂腐......
      【解决方案3】:

      如果可以的话,我建议创建一个日期查找表。创建表一次,然后您可以根据需要经常使用它。如果没有,您需要考虑创建一个Recursive CTE 来充当日期表(很简单——查看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 是日期时间,则需要将其转换为日期。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-25
        • 2022-11-14
        • 1970-01-01
        • 1970-01-01
        • 2015-06-25
        • 1970-01-01
        相关资源
        最近更新 更多