用于报告多个站点分数的滚动平均值的表设计和查询

时间:2014-01-27 22:25:42

标签: sql ms-access ms-access-2007

使用MS Access 2007。

我们为大约50个网站建立了一个指标,每月计算一次并存储在一个表格中。我们希望建立一个生成的报告,以显示上个月的分数以及趋势分别为3个月,6个月和12个月的平均值。首先我们设置如下表,因为使用与UNION ALL连接的四个SELECT TOP N语句,通过SQL计算滚动平均值很容易。

score_date  site1  site2  ...  site50
date1       x1%    x2%         x50%
date2       y1%    y2%         y50%

查询计算滚动平均值:

SELECT roll, AVG(site1) AS site1Avg, AVG(site2) AS site2Avg, etc
FROM (
SELECT TOP 12 'roll12' AS roll, *
FROM tblAuditScore
ORDER BY score_date DESC) AS a
GROUP BY roll

UNION ALL

SELECT roll, AVG(site1) AS site1Avg, AVG(site2) AS site2Avg, etc
FROM (
SELECT TOP 6 'roll06' AS roll, *
FROM tblAuditScore
ORDER BY score_date DESC) AS b
GROUP BY roll

UNION ALL

etc

这适用于计算滚动平均值但我们遇到了一个生成报告的问题,因为没有univot函数,并且使用UNION ALL和PIVOT,如下面链接所示50个站点很麻烦,50个联合查询提取数据从上面的基本查询中查找最后得分,3个月,6个月和12个月的平均值(但如果需要,将使用)。

Access Union/Pivot to Swap Columns and Rows

接下来,我们查看如下所示的表格,可以使用交叉表查询轻松创建原始表格。但是,现在这会导致200个唯一查询,因为每个站点有四个单独的查询,以查找最后得分,3个月,6个月和12个月的平均值。第一种方法至少允许底层查询保持不变。

score_date  site   score
date1       site1  x1%
date1       site2  x2%
date2       site1  y1%

由于分配给我们地区的网站会发生波动,我们目前计划将该表作为记录集循环,并在生成报告之前通过VBA创建几个大量查询。我们是否完全错过了一个简单的解决方案或以错误的方式接近这个?如果需要任何澄清信息,请告诉我们。感谢。

其他信息

源数据是带有输出此信息的UDF的查询

site_code  score_date  audit_score

tblAuditScore是上面两种不同的表格布局

2 个答案:

答案 0 :(得分:0)

我已修改为使用“Iif”(而不是Case /何时是SQL Server)...... 我仍然没有原始数据中明确的列列表。 让我提出以下建议 -

Select
    site,

    AVG(Iif Beg1Mo <= score_date 
    and score_date <= EndDate, score, null) as Last1Mo,

    AVG(Iif Beg3Mo <= score_date 
    and score_date <= EndDate, score, null) as Last3Mo,

    AVG(Iif Beg6Mo <= score_date 
    and score_date <= EndDate, score, null) as Last6Mo,

    AVG(Iif Beg12Mo <= score_date 
    and score_date <= EndDate, score, null) as Last12Mo

From raw_data 
Where    Beg12Mo <= score_date 
  and score_date <= EndDate  
Group by site

在我的下一篇文章中担心计算Beg-date和EndDate

答案 1 :(得分:0)

也许有人会指出更好的方法来做到这一点,但这是我如何解决计算多个网站的滚动平均值。迭代地为每个站点运行查询。快速更改arrMonth字符串可以计算不同的滚动平均值。如果没有计算滚动平均值的足够分数(例如,六个月滚动平均值的四个分数),那么它将不会被记录。

tblAuditScore

score_key           site_code  score_date  audit_score
yyyymm+<site_code>  site1      date        score

tblAuditScoreRoll

roll_key                 site_code  roll_period  roll_date  roll_score
yyyymm+<site_code>+<xx>  site1      period       date       score

以上xx是滚动平均值03,06等的两位数字。期间是您要在报告中使用的字段名称。

Dim rs As Recordset
Dim qdf As QueryDef
Dim strSQL As String
Dim strSQLBase As String
Dim strTable As String
Dim strTableRoll As String
Dim arrMonth() As String
Dim i As Integer

strTable = "tblAuditScore" 'table to store scores
strTableRoll = "tblAuditScoreRoll" 'table to store rolling averages
arrMonth = Split("03,06,12", ",") 'modify array to contain any rolling averages desired

'open query with audit score into recordset
strSQL = "" _
    & "SELECT Format(DATE(),'yyyymm') & site_code AS score_key, " _
        & "site_code, " _
        & "DATE() AS score_date, " _
        & "audit_score " _
        & "score_weight " _
    & "FROM qryAudit_report;"
Set rs = dbLocal.OpenRecordset(strSQL)

'read all plants from query to generate multiple queries to populate table
If Not (rs.EOF And rs.BOF) Then

    'define base SQL string to be used repetitively
    strSQLBase = "" _
        & "SELECT MAX(score_key) & '<<xx>>' AS roll_key, site_code, 'roll<<xx>>' AS roll_period, MAX(score_date) AS roll_date, ROUND(AVG(audit_score),4) AS roll_score " _
        & "FROM (" _
        & "SELECT TOP <<xx>> score_key, site_code, score_date, audit_score " _
        & "FROM " & strTable & " " _
        & "WHERE site_code='<<site_code>>' " _
        & "AND score_date BETWEEN DATESERIAL(YEAR(DATEADD('m',-<<x>>,DATE())),MONTH(DATEADD('m',-<<xx>>,DATE()))+1,1) AND DATE() " _
        & "ORDER BY score_date DESC) AS u<<xx>> " _
        & "GROUP BY site_code " _
        & "HAVING COUNT(audit_score) >= ROUND(<<xx>>*5/6,0) "

    rs.MoveFirst
    Do Until rs.EOF = True

        If DCount("[score_key]", strTable, "[score_key]='" & rs!score_key & "'") = 0 Then
            strSQL = "INSERT INTO " & strTable & " (score_key, site_code, score_date, audit_score, score_weight) " _
                & "SELECT " & rs!score_key & ", " & rs!site_code & ", #" & rs!score_date & "#, " & ROUND(rs!audit_score, 4) & ", " & rs!count_AUFNR & ";"
            dbLocal.Execute strSQL, dbFailOnError

            strSQL = "" 'clear string
            'generate SQL for all rolling averages defined
            For i = LBound(arrMonth) To UBound(arrMonth)
                strSQL = strSQL & Replace(Replace(strSQLBase, "<<xx>>", arrMonth(i)), "<<site_code>>", rs!site_code) _
                    & vbNewLine & vbNewLine & "UNION ALL "
            Next i

            'remove trailing UNION ALL
            strSQL = Left(strSQL, Len(strSQL) - 14)
            'insert results into table
            strSQL = "INSERT INTO " & strTableRoll & " (roll_key, site_code, roll_period, roll_date, roll_score) " _
                & "SELECT * FROM (" & strSQL & ") AS q;"

            'create temp query to insert rolling average into table
            Set qdf = dbLocal.CreateQueryDef("")
            With qdf
                .SQL = strSQL
                .Execute dbFailOnError
                .Close
            End With

        End If

        rs.MoveNext

    Loop

'add code to export report

Else
    MsgBox "There are no records in the query to store in " & strTable
End If

rs.Close
Set rs = Nothing

<强> TLDR

以上六个月滚动平均示例中,上述循环遍历所有每个滚动平均值的站点:

SELECT MAX(score_key) & '06' AS roll_key, site_code, 'roll06' AS roll_period, MAX(score_date) AS roll_date, ROUND(AVG(audit_score),4) AS roll_score 
FROM (
SELECT TOP 06 score_key, site_code, score_date, audit_score 
FROM strTable  
WHERE site_code='<<site_code>>' 
AND score_date BETWEEN DATESERIAL(YEAR(DATEADD('m',-6,DATE())),MONTH(DATEADD('m',-6,DATE()))+1,1) AND DATE() 
ORDER BY score_date DESC) AS u
GROUP BY site_code
HAVING COUNT(audit_score) >= 5