1

FirewallLog と ProxyLog という 2 つの異なるテーブルがあります。これら 2 つのテーブルの間には関係はありません。これらには 4 つの共通フィールドがあります。

LogTime ClientIP BytesSent BytesRec

特定の ClientIP の合計使用量を一定期間 (先月など) に毎日計算し、以下のように表示する必要があります。

日付 TotalUsage
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) です。その日の使用がない(記録がない)場合は、ゼロを表示する必要があります。この問題に対する最速の解決策を見つける必要があります。何か案は?

4

3 に答える 3

3

まず、カレンダー テーブルを作成します。少なくとも、id列とcalendar_date列があり、関心のある毎年の毎日をカバーする日付で埋めます(週末、銀行休日、および日付に関するその他のあらゆる種類の有用なメタデータのフラグを追加することがわかります。)

次に、2 つのテーブルを 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」がすべて含まれていることを前提としています。

これは、2 つの値も含めたい場合に備えて (たとえば、どちらが合計に多くのバイト数を与えているかを確認するため)、2 つの値も分割します。

于 2013-07-11T01:43:42.637 に答える
1

オプションである場合は、日付ルックアップ テーブルを作成することをお勧めします。テーブルを一度作成すれば、必要に応じて何度でも使用できます。そうでない場合は、 Dates テーブルとして機能する を作成することを検討する必要があり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 が日時の場合は、日付に変換する必要があります。

于 2013-07-11T01:39:14.363 に答える