【问题标题】:PHP/mysql checking all dates are accounted forPHP/mysql 检查所有日期
【发布时间】:2014-12-30 00:12:02
【问题描述】:

我有一个应用程序,我希望用户在其中输入工作历史记录。我使用 DATE 格式(每个作业的 start_date 和 end_date)将结果存储在 mysql 表中。因此,例如,在几个条目之后,它可能看起来像这样(job_history 表:

Job             Start              End
Dishwasher      2013-07-10         2014-03-28
Banker          2014-04-02         2014-10-10
Cahsier         2014-10-11         2014-12-20

我正在尝试设置一个 mysql 查询,该查询将检查某年是否缺少任何天数。对于我们的示例,让我们使用 2014。从 2014-03-29 到 2014-04-01 有缺失的天数。

我无法通过搜索找到任何好的示例。我认为有比 PHP 循环和 365 查询更好的方法(哎呀!)。谢谢

编辑:更新示例以合并年初和年终:

Job             Start              End
Dishwasher      2013-07-10         2013-12-01
Banker          2014-01-10         2014-10-10
Cahsier         2014-10-11         2014-12-20

在此示例中,我们的输入年份为 2014 年,我们将在年初有 9 天未被发现,而在年底有 11 天。

【问题讨论】:

  • 为什么不使用 mysql DISTINCT 然后在结果中循环查找 php.ini 中缺少的日期。它仍然是一个查询,但您可以在 php 代码中管理逻辑。
  • 工作类型总是只有 3 种吗?例如洗碗机、银行家和收银员?如果是这样,您可能可以创建一个交叉表查询,然后处理。
  • 您有唯一标识符列吗?像作为主键的表中的 ID?
  • DISTINCT 的想法很有趣,除非出现更好的东西,否则可以尝试一下。可以有无限数量的作业类型。是的,我有一个唯一的 ID 列
  • 如果工作类型的数量不受限制,交叉表将不起作用,因此我同意 Chuck 的建议。为什么会循环 365 查询?

标签: php mysql date


【解决方案1】:

对于后来提出这个问题的人来说,最初的答案是这样的

SELECT jh.id,
    CASE
        WHEN datediff(jh1.start, jh.end) > 1
        THEN datediff(jh1.start, jh.end)
        ELSE NULL
    END as DifferenceInDays
FROM job_history jh
LEFT JOIN job_history jh1 ON jh1.id = (jh.id + 1)

它的作用是假设一个顺序 id 来自我加入,这样您就可以将最后一行日期与当前行日期进行比较。

在对要求进行大量添加之后,这将满足您的需求。

SELECT position, id, DifferenceInDays
FROM
(       SELECT 'BEGINNING' as position, id,
            @a := if(@a = 'BAD', 'BAD', if(DATE(concat(year(now()), '-01-01')) BETWEEN start AND end, 'BAD', '')),
            case
                WHEN @a = 'BAD'
                THEN NULL
                ELSE datediff(jstart, DATE(concat(year(now()), '-01-01')))
            end AS DifferenceInDays
        FROM
        (   SELECT jh.*, jh3.start as jstart
            FROM job_history jh
            CROSS JOIN(SELECT @a:='')t
            LEFT JOIN (SELECT min(start) as start FROM job_history where userid = 123456 AND YEAR(start) = YEAR(NOW())) jh3 ON jh3.start = jh.start
            WHERE jh.userid = 123456
            ORDER BY id
        )t
    UNION ALL
        SELECT 'MIDDLE', jh.id, '',
            case
                WHEN datediff(jh1.start, jh.end) > 1
                THEN datediff(jh1.start, jh.end) - 1
                ELSE NULL
            end as DifferenceInDays
        FROM
        (   SELECT *, @new_id := @new_id + 1 as new_id
            FROM job_history, (select @new_id := 0) temp
            WHERE userid = 123456
        ) jh
        LEFT JOIN 
        (   SELECT *, @new_id1 := @new_id1 + 1 as new_id
            FROM job_history, (select @new_id1 := 0) temp
            WHERE userid = 123456
        ) jh1 ON jh1.new_id = (jh.new_id + 1)

    UNION ALL
        SELECT 'ENDING', id, 
            @b := if(@b = 'BAD', 'BAD', if(DATE(concat(year(now()), '-12-31')) BETWEEN start AND end, 'BAD', '')),
            case
                WHEN @b = 'BAD'
                THEN NULL
                ELSE datediff(DATE(concat(year(now()), '-12-31')), jend)
            end
        FROM
        (   SELECT jh.*, jh2.end as jend
            FROM job_history jh
            CROSS JOIN(SELECT @b:='')t
            LEFT JOIN (SELECT max(end) as end FROM job_history WHERE userid = 123456) jh2 ON jh2.end = jh.end
            WHERE jh.userid = 123456
            ORDER BY id
        )t
    ORDER BY case position WHEN 'BEGINNING' THEN 1 WHEN 'MIDDLE' THEN 2 ELSE 3 END ASC, id ASC
) t
WHERE DifferenceInDays IS NOT NULL

FIDDLE WITH MULTIPLE ROWS

FIDDLE WITH ONLY MIDDLE AND END

FIDDLE WITH NO MIDDLE ONE ROW

FIDDLE WITH ALL THREE

FIDDLE WITH NO END

【讨论】:

  • 谢谢你和小提琴。但是,如果我将上一份工作更改为 2014 年 12 月 20 日而不是 2014 年 12 月 31 日结束,则此方法不会计算年底的缺失天数
  • @phpmysqlguy 这是一个不同的要求。你如何确定使用哪一年?你有从 2013 年到 2014 年。如果你愿意,我可以包括到 current_day,但有什么要求?今年年底?明年年底?
  • @phpmysqlguy 查看我的编辑,以了解包含到当前年份的方法。
  • 认为你在正确的轨道上,很棒的东西(谢谢)。但是,使用您的最新版本,我更新了您的小提琴并编辑了我的原始帖子以反映未涵盖的年底(截至 2014 年 12 月 20 日)。在示例中,它应该返回 4,然后在最后返回 11 天。我认为您的代码返回 4,然后返回 10。
  • @phpmysqlguy 运行这个。 select datediff('2014-12-31', '2014-12-20'), datediff('2014-04-02','2014-03-28') 你会看到它在两者上都被包容地处理。我对两者都做了负 1 以返回不包含在内的天数
【解决方案2】:

您可以使用date_diff 函数来查找两个日期之间的差异

$interval = date_diff($datetime1, $datetime2);

【讨论】:

  • 我知道 date_diff,但不知道这是如何回答问题的
猜你喜欢
  • 2015-04-29
  • 1970-01-01
  • 2012-10-17
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-16
相关资源
最近更新 更多