【问题标题】:get number of occurrences taking 1 for every 3 days group获取每 3 天组 1 次的出现次数
【发布时间】:2014-06-21 07:12:04
【问题描述】:

我为通常上班迟到的员工准备了一张桌子。我需要向人力资源部发送一份报告,显示每个迟到的用户,考虑到如果该用户在 3 天内至少迟到 1 次,我只能计算每个用户的警告。

我需要的第一个数据是要发送给 HR 经理以评估全局“迟到”的警告总数。

仅迟到一天的用户将收到一条警告,但如果他们迟到两次或更多次,他们将收到的警告取决于他们是否在从第一天算起的 3 天内收到警告。

我们来看一个例子:

  • 乔 9 号星期一
  • 标记星期一 9 号
  • 蒂姆星期一 9 号
  • 乔 10 号星期二
  • 乔 11 号星期三
  • 乔 12 日星期四
  • 提姆星期五 13 号

以上表数据为例。

Joe 将收到 2 个警告:第一个是星期一,第二个是星期四。周二和周三将被丢弃,因为它们属于同一个 3 天期间。

Mark 在星期一只会收到一条警告。

蒂姆将收到 2 条警告。第一个在星期一,第二个在星期五。

也许使用标准 sql 查询无法获得这个数字,需要完成一些游标。

提前致谢

【问题讨论】:

  • 您使用的是哪个 RDBMS?
  • “3 天期限”是固定间隔还是滚动窗口?

标签: sql


【解决方案1】:

好的...这里缺少一些信息,正如两个 cmets(Quassnoi 和 Mr. Llama)中正确说明的那样。

使用中的 RDBMS 可能会影响解决方案,因为这与日期函数和日期代数有关,并且并非所有 RDBMS 都共享相同的扩展函数集。 我假设是 MySQL 5.5,它很常见,可以在 SQLFiddle 上进行测试。

您的 3 天期限也有点模糊。是所有员工都一样,还是取决于什么?是三天,还是半周(周一-周三,周四-周六)?之后会发生什么?我们是否使用 sun-tue,然后是 wed-fried 等等? 我假设所有员工的半周(周日-周三、周四-周六)都是一样的。`所以一个时期是按年、一年中的一周、半周来确定的。

您应该澄清的最后一点是预期的结果集。你想要一个警告日列表还是计数或什么? 我已经假设了一个带有每个日期的警告列表(我已经为每个员工和期间的组合取了第一个日期)。

使用以下语句创建示例数据集:

CREATE TABLE LateEntrances (
  Employee VARCHAR(20),
  DateLate DATE
);
INSERT INTO LateEntrances VALUES('Joe' ,'2014.06.09');
INSERT INTO LateEntrances VALUES('Mark','2014.06.09');
INSERT INTO LateEntrances VALUES('Tim' ,'2014.06.09');
INSERT INTO LateEntrances VALUES('Joe' ,'2014.06.10');
INSERT INTO LateEntrances VALUES('Joe' ,'2014.06.11');
INSERT INTO LateEntrances VALUES('Joe' ,'2014.06.12');
INSERT INTO LateEntrances VALUES('Tim' ,'2014.06.13');

以下查询解决了您的问题:

SELECT i.Employee, i.YearLate, i.WeekLate, i.PeriodLate, MIN(i.DateLate)
FROM (
  SELECT Employee, DateLate,
    YEAR(DateLate)               AS YearLate,
    WEEKOFYEAR(DateLate)         AS WeekLate,
    FLOOR(DAYOFWEEK(DateLate)/4) AS PeriodLate
  FROM LateEntrances
) i
GROUP BY i.Employee, i.YearLate, i.WeekLate, i.PeriodLate;

(SQLFiddle here)

YearLate、WeekLate 和 PeriodLate 三列标识警告期。您可以将它们连接在一个周期标识列中:

SELECT i.Employee, i.PeriodLate, MIN(i.DateLate)
FROM (
  SELECT Employee, DateLate,
    CONCAT_WS('*',
      YEAR(DateLate)              ,
      WEEKOFYEAR(DateLate)        ,
      FLOOR(DAYOFWEEK(DateLate)/4)
    ) AS PeriodLate
  FROM LateEntrances
) i
GROUP BY i.Employee, i.PeriodLate;

...或者您可以将它们一起隐藏(在 SELECT 中),即使您仍然必须使用它们来进行 GROUP BY:

SELECT i.Employee, MIN(i.DateLate)
FROM (
  SELECT Employee, DateLate,
    CONCAT_WS('*',
      YEAR(DateLate)              ,
      WEEKOFYEAR(DateLate)        ,
      FLOOR(DAYOFWEEK(DateLate)/4)
    ) AS PeriodLate
  FROM LateEntrances
) i
GROUP BY i.Employee, i.PeriodLate;

您还可以轻松地将周期计算逻辑更改为其他内容,例如严格的一年中的 3 天或每月 3 天的周期。有很多可能性。

...根据我所做的假设。清除开放点,我会尽力使答案更好。但与此同时,这应该足以让您入门。

【讨论】:

    猜你喜欢
    • 2021-10-30
    • 2016-09-08
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2013-09-09
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    相关资源
    最近更新 更多