【问题标题】:Access SQL count number of people group by week number访问 SQL 计数人数按周数分组
【发布时间】:2016-08-15 20:32:48
【问题描述】:

给定一周的数字,我需要计算有多少人在工作。

这是我的人员表(日期为美国格式):

name | surname| date_of_entry | date_of_exit
-----|--------|---------------|-------------
foo  | bar    | 1/1/2006      | 1/8/2006
foo1 | bar1   | 1/5/2010      |
foo2 | bar2   | 2/3/2015      | 3/4/2015

并且我希望给定年份的所有周数以及在此期间工作的适当人数。
我希望你能理解我,因为英语不是我的母语抱歉。

我已经做了一些研究,据我了解,我需要根据示例创建一个从 2006 年 1 月 1 日开始到“现在”结束的所有周的表格(因为没有退出日期的人仍在工作)上面可以测试每个人是否在这周工作,这样我就可以在我的查询中计算他。

我仍然是一名学生程序员,但对我来说这似乎是一个相当复杂的 SQL 查询。

2006 年查询的预期输出(新年从星期一开始):

week_number | count
------------|------
   1        | 1
   2        | 1
   3        | 0
   etc..    | 0

直到 2010 年 1 月 5 日,所有周在“计数”字段中都有 1 然后查询 2015 年:

week_number | count
------------|------
   1        | 1
   2        | 1
   ...      | 1
   9        | 2
   ...      | 2
   14       | 1
   ...      | 1

如果有人能帮我解决这个问题,那就太好了,谢谢!

【问题讨论】:

  • 您还需要 ,因为标准 ISO 周跨越日历年的界限。或者,如果您有自定义周数,请展开周表以保存一周的开始日期和/或结束日期。此外,您必须定义“一周工作”是指工作一整周还是只工作一部分。
  • 目前,我的周表有四个字段:year、week_number、week_start、week_end,我目前正在尝试使用 VBA 代码填充它。 “一周工作”对我来说也是模棱两可的,但假设有人工作超过 3 天,那么他就是在工作整整一周(如果这不是太复杂的话)。

标签: sql ms-access


【解决方案1】:

你很幸运,我必须在 15 分钟内改变主意。


第 1 步:创建日历表

使用以下字段创建一个名为 Calendar 的新表

  • id:自动编号
  • Cal_Year:号码
  • Cal_Week:号码

在一个模块中,添加以下代码并执行它(F5):

Private Sub Create_Calendar_table()

    Dim Y As Integer
    Dim W As Integer

    For Y = 2006 To 2016
        For W = 1 To 52
            DoCmd.RunSQL "INSERT INTO Calendar (cal_year, cal_week) VALUES (" & Y & "," & W & ")"
        Next W
    Next Y

End Sub

Calendar 表现在可以使用了:

ID  Cal_year    Cal_week
1   2006        1
2   2006        2
3   2006        3
4   2006        4
5   2006        5
    and so on...

第 2 步:创建查询

请注意,我在欧洲,所以我的日期是 DD/MM。这不会影响您的结果。

我分解让你了解这个过程。

首先我们需要从日历表中的年/周创建一个日期,可以这样实现

SELECT Cal_year, Cal_week, DateAdd("ww",Cal_week,DateSerial(Cal_year,1,1)) AS thedate
FROM Calendar

Cal_year    Cal_week    thedate
2006            1       8/01/2006
2006            2       15/01/2006
2006            3       22/01/2006
2006            4       29/01/2006
2006            5       5/02/2006   
and so on...

接下来,由于我们将处理日期范围,因此当人们的 exit_date 为 NULL 时,将 当前日期 归类很重要,如下所示:

nz(date_of_exit, Now)

字段已准备好。

然后,诀窍。

我们需要JOIN 我们的日历表和人员表,其方式将返回一个人在场的每周记录。

实现这一点的关键是ON...BETWEEN...AND

SELECT C.Cal_year, C.Cal_Week, P.pname, P.psurname, P.date_of_entry, nz(P.date_of_exit, Now) AS exit_date
FROM [Calendar] C
INNER JOIN ( SELECT [Name] AS pname, [surname] as psurname, date_of_entry, date_of_exit
            FROM people
           ) P  
ON (DateAdd("ww",C.Cal_week,DateSerial(C.Cal_year,1,1)) BETWEEN P.date_of_entry  AND nz(P.date_of_exit, Now))
ORDER BY  C.Cal_year, C.Cal_Week             

Cal_year    Cal_Week pname      psurname    date_of_entry       exit_date
2006            1   foo         bar         1/01/2006               8/01/2006
2010            1   foo1        bar1        5/01/2010               22/04/2016 13:04:39
2010            2   foo1        bar1        5/01/2010               22/04/2016 13:04:39
2010            3   foo1        bar1        5/01/2010               22/04/2016 13:04:39
2010            4   foo1        bar1        5/01/2010               22/04/2016 13:04:39

请注意,如果您需要自 2006 年以来的所有星期,即使是那些没有人在场的,只需将 INNER JOIN 更改为 LEFT JOIN

最后,我们利用前面的查询通过在日历表的年份和星期上执行GROUP BY 来计算出现次数,并且我们在WHERE 子句中指定 2015 年,否则它将计算自 2006 年以来的所有内容。这意味着很容易计算任何一年的存在。

SELECT yyyy, ww , count(*) AS cnt
FROM
(         
    SELECT C.Cal_year AS yyyy, C.Cal_Week AS ww
    FROM [Calendar] C
    INNER JOIN ( SELECT [Name] AS pname, [surname] as psurname, 
                       date_of_entry,  
                       date_of_exit
                FROM people
               ) P  ON (DateAdd("ww",C.Cal_week,DateSerial(C.Cal_year,1,1)) BETWEEN P.date_of_entry  AND nz(P.date_of_exit, Now))
)
WHERE yyyy=2015
GROUP BY yyyy, ww
ORDER BY yyyy, ww

yyyy    ww  cnt
2015    1   1
2015    2   1
2015    3   1
2015    4   1
2015    5   1
2015    6   1
2015    7   1
2015    8   1
2015    9   2
2015    10  2
2015    11  2
2015    12  2
2015    13  2
2015    14  1
2015    15  1
2015    16  1   

好吧,我终于花了 40 分钟......

【讨论】:

  • 感谢伙伴,它工作得很好,我只是用 = 运算符替换了 between,因为访问给了我一个错误“在查询表达式中没有 AND 的运算符之间”,但现在一切都很好!
  • @zogota 奇怪...我在 Access 2010 上测试了所有内容
  • 我正在使用 access 2013 并且当我进入查询生成器然后退出或者当我在表视图中尝试“GUI”排序时发生这种情况,我认为这是一个错误,其中 ms 访问添加括号查询不应该在哪里,然后一切都失败了,但这不再是问题了。由于“dateadd”函数和 BETWEEN 运算符,我仍然很难理解连接是如何工作的,我以前从未做过这样的事情。我的另一个问题是日历表中 id 的目的是什么?我使用 cal_week 和 cal_year 作为 PK,我尝试使用 auto-id 但它似乎并不快。
  • @zogota cal 表的 id 在这里没有特定用途,我只是有一个习惯,总是在我的表中进行技术 PK。如果需要,您可以删除此列。关于错误...我每天都在思考 MS 访问错误,所以这是一个可能的解释。您可以做的是使用INNER JOIN BETWEEN AND 查询创建一个查询。然后最后一个查询将变为SELECT yyyy, ww , count(*) AS cnt FROM thequery WHERE yyyy=2015 GROUP BY yyyy, ww。这可能会解决一些问题并提供更大的灵活性(例如,如果您想查询另一年或特定周)
【解决方案2】:

您可以创建一个查询来查找工作周数:

Select 
    [name],
    surname,
    year,
    week
From
    PeopleTable,
    WeekTable
Where
    (date_of_entry <= week_start And DateDiff("d", week_start, date_of_exit) >= 3)
        Or
    (date_of_entry >= week_start And date_of_exit <= week_end
    And
    DateDiff("d", date_of_entry, date_of_exit >= 3)
        Or
    (DateDiff("d", date_of_entry, week_end) >= 3 And date_of_exit >= week_end)        
Group By
    [name],
    surname,
    year,
    week        

现在,保存并创建一个新查询,在其中使用 WeekTable 作为源(列出所有周),并与上面的查询进行外部连接(列出工作周)。在此,按年和周分组并添加计数以获取每周工作员工的计数。

【讨论】:

  • 感谢您的帮助,我仍然使用 Thomas 的解决方案,因为您不需要存储 week_startweek_end
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 2010-11-30
  • 1970-01-01
  • 2014-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多