【问题标题】:Calculate clients per week based on start date and end date in MS Access根据 MS Access 中的开始日期和结束日期计算每周的客户
【发布时间】:2017-12-29 09:51:26
【问题描述】:

在 MS Access 数据库中,我有关于客户到达和离开日期的信息。基于此,我想计算每周访问的客户数量。

考虑下面的例子。彼得在一月的第一周到达并在第三周离开(每周从星期日开始)。另一方面,玛丽在第一周到达并离开。

我希望输出如下所示,第一列是周数,第二列是客人总数。

请问实现这一目标的最佳方法是什么?

【问题讨论】:

  • 您希望在 SQL 或 Access 中完成此操作?
  • 第一周是从 2017 年 12 月 31 日还是 1 月 7 日开始?
  • 德国第一周从 2018 年 1 月 1 日开始
  • @twyly。正在考虑像DatePart("ww",[arrival]) DatePart function 这样的东西会起作用。如果 OP 希望这一年从星期日开始,firstweekofyear 参数可能会有点问题。
  • 我想DatePart("ww",[arrival]-Weekday([arrival],1)+7) 会给你周数。您可能必须将它加入到包含第 1 到第 53 周的表中,以便它包含到达和离开日期之间的所有周数。

标签: sql database ms-access group-by


【解决方案1】:

我的德国日期格式的解决方案,用 ORACLE 测试。我每周都会建立一些日历表(tw_test_week)来加入它。

CREATE TABLE tw_test_client (
 client VARCHAR2(10),
 arrival DATE,
 departure DATE
);

INSERT INTO tw_test_client VALUES
( 'Peter', to_date('01.01.2018','DD.MM.YYYY'), to_date('11.01.2018','DD.MM.YYYY'));

INSERT INTO tw_test_client VALUES
( 'Mary', to_date('01.01.2018','DD.MM.YYYY'), to_date('01.02.2018','DD.MM.YYYY'));

CREATE TABLE tw_test_week (
 weekid INT,
 started DATE,
 ended DATE
);

INSERT INTO tw_test_week VALUES
( to_char(to_date('01.01.2018','DD.MM.YYYY'),'WW'),
  to_date('01.01.2018','DD.MM.YYYY'), 
  to_date('07.01.2018','DD.MM.YYYY')
);

INSERT INTO tw_test_week VALUES
( to_char(to_date('08.01.2018','DD.MM.YYYY'),'WW'),
  to_date('08.01.2018','DD.MM.YYYY'), 
  to_date('14.01.2018','DD.MM.YYYY')
);

INSERT INTO tw_test_week VALUES
( to_char(to_date('15.01.2018','DD.MM.YYYY'),'WW'),
  to_date('15.01.2018','DD.MM.YYYY'), 
  to_date('21.01.2018','DD.MM.YYYY')
);

INSERT INTO tw_test_week VALUES
( to_char(to_date('22.01.2018','DD.MM.YYYY'),'WW'),
  to_date('22.01.2018','DD.MM.YYYY'), 
  to_date('28.01.2018','DD.MM.YYYY')
);

INSERT INTO tw_test_week VALUES
( to_char(to_date('29.01.2018','DD.MM.YYYY'),'WW'),
  to_date('29.01.2018','DD.MM.YYYY'), 
  to_date('04.02.2018','DD.MM.YYYY')
);

SELECT w.weekid, COUNT(*) 
  FROM tw_test_week w
  JOIN tw_test_client c
    ON w.started BETWEEN c.arrival and c.departure
GROUP BY w.weekid
ORDER BY w.weekid;

结果

WEEKID  COUNT
1   2
2   2
3   1
4   1
5   1

【讨论】:

  • 感谢您的建议,但我希望有一些更具可扩展性的东西。如果我想检查接下来 100 周的计数,根据您的建议,我需要在 tw_test_week 中手动创建 100 条记录。
【解决方案2】:

创建一个包含数字 1 到 53 的表。在我的查询中,这个表称为 WeekNumTable,并包含一个字段,其中列出了每个星期的数字。

SELECT      WeekNum
            , COUNT(WeekNum) AS TotalClients
FROM        WeekNumTable INNER JOIN ClientTable ON 
                WeekNumTable.WeekNum>=DatePart("ww",ClientTable.Arrival-Weekday(ClientTable.Arrival,1)+7) AND
                WeekNumTable.WeekNum<=DatePart("ww",ClientTable.Departure-Weekday(ClientTable.Departure,1)+7)
GROUP BY    WeekNum  

您的示例让我有些困惑,因为您将第 3 周列为有 1 个客户,而数据表没有。

编辑:我可以看到的一个问题是,如果您确实想查看接下来的 100 周,则需要将年份分开,否则第一周与这两年将混为一谈。

【讨论】:

    【解决方案3】:

    您可以使用一系列查询来获取此信息。

    首先,创建一个名为Ten的查询:

    SELECT DISTINCT Abs([id] Mod 10) AS N
    FROM MSysObjects;
    

    然后您可以创建一个查询,ClientDays,列出您从第一次到达到最后一次离开之间的所有日期:

    SELECT DISTINCT 
        [Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100 AS Id, 
        DateAdd("d",[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100,[StartDate]) AS [Date]
    FROM 
        Ten AS Ten_0, 
        Ten AS Ten_1, 
        Ten AS Ten_2, 
        (Select 
            Min([Arrival]) As StartDate, 
            DateDiff("d", Min([Arrival]), Max([Departure])) As Days 
        From 
            ClientDates) AS T
    WHERE 
        ((([Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100)<=[Days]) 
        AND 
        ((Ten_0.N)<=[Days]\1) 
        AND 
        ((Ten_1.N)<=[Days]\10) 
        AND 
        ((Ten_2.N)<=[Days]\100));
    

    在查询 ClientWeeks 中使用它来查找周数:

    SELECT 
        Year([Date]) AS [Year], 
        DatePart("ww",[Date]) AS Week, 
        ClientDates.Client
    FROM 
        ClientDays, 
        ClientDates
    WHERE 
        ClientDays.Date Between [Arrival] And [Departure]
    GROUP BY 
        Year([Date]), 
        DatePart("ww",[Date]), 
        ClientDates.Client;
    

    最后,计算客户数:

    SELECT 
        ClientWeeks.Year, 
        ClientWeeks.Week, 
        Count(ClientWeeks.Client) AS TotalClients
    FROM 
        ClientWeeks
    GROUP BY 
        ClientWeeks.Year, 
        ClientWeeks.Week;
    

    请注意,由于您打算使用不一致的周编号方法,因此您将难以在新年前后进行计数。

    唯一明确的周数是 yyyy-wwISO-8601 系统,因为第一周和/或最后一周将跨越日历年的界限。

    如果您希望实现这一点,请留下注释,因为它无法使用原生 VBA 函数完成;必须使用自定义函数,但如果您不使用它们,我不希望在此处发布它们。

    【讨论】:

    猜你喜欢
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多