sql 时间计算,有以下一个每天的刷卡时间表,求每天上班上了多少个小时的sql 语句

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql 时间计算,有以下一个每天的刷卡时间表,求每天上班上了多少个小时的sql 语句相关的知识,希望对你有一定的参考价值。

5378 2011.08.01 0757 07:57 201108010757 6 003765 1080113:40 A .0 01
5378 2011.08.01 1201 12:01 201108011201 6 003765 1080208:24 A .0 NULL 01
5378 2011.08.01 1255 12:55 201108011255 6 003765 1080208:24 A .0 NULL 01
5378 2011.08.01 1801 18:01 201108011801 6 003765 1080208:24 A .0 01
5378 2011.08.02 0757 07:57 201108020757 6 003765 1080208:24 A .0 01
5378 2011.08.02 1200 12:00 201108021200 6 003765 1080417:24 A .0 01
5378 2011.08.02 1254 12:54 201108021254 6 003765 1080417:24 A .0 01
5378 2011.08.02 1809 18:09 201108021809 6 003765 1080417:24 A .0 01
5378 2011.08.03 0758 07:58 201108030758 6 003765 1080417:24 A .0 01
5378 2011.08.03 1200 12:00 201108031200 6 003765 1080417:24 A .0 NULL 01
5378 2011.08.03 1255 12:55 201108031255 6 003765 1080417:24 A .0 01
5378 2011.08.03 1806 18:06 201108031806 6 003765 1080417:24 A .0 01
5378 2011.08.04 0755 07:55 201108040755 6 003765 1080417:24 A .0 01
5378 2011.08.04 1200 12:00 201108041200 6 003765 1080417:24 A .0 01
5378 2011.08.04 1256 12:56 201108041256 6 003765 1080417:24 A .0 01
5378 2011.08.04 1800 18:00 201108041800 6 003765 1080614:48 A .0

没有提供字段名,不方便描述。
假设员工都是上白班,早上上班,下午下班;便可以得出一个结论,每天最早的刷卡记录就是上班时刷的,每天最晚的刷卡记录便是下班记录,不理会中间刷了几次。
1. 先按工号和日子分组,同一天的记录分到一个组,求最早记录和最晚记录。
select emp_id, cast(convert(varchar(10),punch_time,102) as datetime) as workday, min(punch_time) as punch_in, max(punch_time) as punch_out
from TableName
group by emp_id, cast(convert(varchar(10),punch_time,102) as datetime)

-- 其中语句cast(convert(varchar(10),punch_time,102) as datetime) 是去掉打卡时间字段里的时间部分,只保留日期部分,使同一天的记录聚合到同一个组内。

2. 用下班时间减去上班时间就得出上班的小时数。完整的SQL语句如下:
select emp_id, cast(convert(varchar(10),punch_time,102) as datetime) as workday, datediff(hour,min(punch_time) , max(punch_time) ) as hours
from TableName
group by emp_id, cast(convert(varchar(10),punch_time,102) as datetime)

如果有夜班(即跨24:00的班次),就复杂一些了,需要额外处理。
参考技术A use Tempdb%Ago%A--> --> %A %Aif not object_id(N'Tempdb..#Tab') is null%A%9drop table #Tab%AGo%ACreate table #Tab([ID] int,[Name] nvarchar(2),[Logtime] Datetime,[action] nvarchar(2))%AInsert #Tab%Aselect 1,N'张三','2011-08-24 08:00',N'登录' union all%Aselect 2,N'张三','2011-08-24 08:31',N'登录' union all%Aselect 3,N'张三','2011-08-24 09:20',N'离开' union all%Aselect 4,N'张三','2011-08-24 09:29',N'登录' union all%Aselect 5,N'张三','2011-08-24 13:50',N'离开' union all%Aselect 6,N'张三','2011-08-24 14:20',N'登录' union all%Aselect 7,N'张三','2011-08-24 15:20',N'登录' union all%Aselect 8,N'张三','2011-08-24 16:30',N'离开' union all%Aselect 9,N'张三','2011-08-24 08:00',N'登录' union all%Aselect 10,N'陶明','2011-08-24 07:31',N'登录' union all%Aselect 11,N'陶明','2011-08-24 08:20',N'离开' union all%Aselect 12,N'陶明','2011-08-24 09:50',N'登录' union all%Aselect 13,N'陶明','2011-08-24 15:50',N'离开' union all%Aselect 14,N'陶明','2011-08-24 16:10',N'离开' union all%Aselect 15,N'陶明','2011-08-24 16:42',N'离开'%AGo%ASelect %A%9CONVERT(VARCHAR(8),[Logtime],112) AS 日期,%A%9[Name] AS 姓名,%A%9min(CASE WHEN [action]=N'登录' THEN convert(varchar(8),[Logtime],8) END) AS 最早上班时间,%A%9max(CASE WHEN [action]=N'离开' THEN convert(varchar(8),[Logtime],8) END) AS 最晚下班时间%Afrom #Tab%AWHERE CONVERT(VARCHAR(8),[Logtime],112)='20110824'%AGROUP BY CONVERT(VARCHAR(8),[Logtime],112),[Name]%A%A/*%A日期%9姓名%9最早上班时间%9最晚下班时间%A20110824%9陶明%907:31:00%916:42:00%A20110824%9张三%908:00:00%916:30:00%A*/

参考资料:百度一下

在 SQL 中的日期之间每天计算用户留存率

【中文标题】在 SQL 中的日期之间每天计算用户留存率【英文标题】:Calculating user retention on daily basis between the dates in SQL 【发布时间】:2021-09-26 17:25:07 【问题描述】:

我有一个表,其中包含有关 user_ids 的数据,以及他们所有最后登录到应用程序的日期

表:

|----------|--------------|
| User_Id  | log_in_dates |
|----------|--------------|
|   1      |  2021-09-01  |
|   1      |  2021-09-03  |
|   2      |  2021-09-02  |
|   2      |  2021-09-04  |
|   3      |  2021-09-01  |
|   3      |  2021-09-02  |
|   3      |  2021-09-03  |
|   3      |  2021-09-04  |
|   4      |  2021-09-03  |
|   4      |  2021-09-04  |
|   5      |  2021-09-01  |
|   6      |  2021-09-01  |
|   6      |  2021-09-09  |
|----------|--------------|

从上表中,我试图了解用户从今天到过去 90 天的登录行为。

Num_users_no_log_in 定义了从present_day 到前几天 (last_log_in_date) 尚未登录应用的用户数

我想要如下表:

|---------------|------------------|--------------------|-------------------------|
| present_date  | days_difference  | last_log_in_date   |  Num_users_no_log_in    |
|---------------|------------------|--------------------|-------------------------|
|  2021-09-01   |       0          |    2021-09-01      |         0               |
|  2021-09-02   |       1          |    2021-09-01      |         3               |->(Id = 1,5,6)
|  2021-09-02   |       0          |    2021-09-02      |         3               |->(Id = 1,5,6)
|  2021-09-03   |       2          |    2021-09-01      |         2               |->(Id = 5,6)  
|  2021-09-03   |       1          |    2021-09-02      |         1               |->(Id = 2)    
|  2021-09-03   |       0          |    2021-09-03      |         3               |->(Id = 2,5,6)
|  2021-09-04   |       3          |    2021-09-01      |         2               |->(Id = 5,6)  
|  2021-09-04   |       2          |    2021-09-02      |         0               |
|  2021-09-04   |       1          |    2021-09-03      |         1               |->(Id= 1)     
|  2021-09-04   |       0          |    2021-09-04      |         3               |->(Id = 1,5,6)
|    ....       |       ....       |        ....        |         ....  
|---------------|------------------|--------------------|-------------------------|

我能够使用以下查询获得前三列 Present_date | days_difference | last_log_in_date

with dts as
(
    select distinct log_in from users_table
)
select x.log_in_dates as present_date,
       DATEDIFF(DAY, y.log_in_dates ,x.log_in_dates ) as Days_since_last_log_in,
       y.log_in_dates as log_in_dates 
       from dts x, dts y
       where x.log_in_dates >= y.log_in_dates

不明白怎么才能得到第四列Num_users_no_log_in

【问题讨论】:

您的示例数据不适用于您的示例查询,请检查您的代码和数据,使其重现您在问题中包含的内容。 @Stu 我已经包含了样本表直到2021-09-04,它是正确的 你需要解释每一行的预期结果 【参考方案1】:

我不太了解您的需求:是否存在基于用户或日期的值?它基于日期,看起来像(在其他地方您可能会将 user_id 作为第一列),具有多次相同日期是什么意思?我知道您想回顾一下从开始到当前日期的所有日期,但在我看来这并没有什么意义(想象一下您的仪表板在 1 年后!!)

说了这么多,让我们来看看方法吧。 在这种情况下,我使用common table extensions 逐步开发。例如,它需要 3 个步骤:

准备时间序列 整合连接的日期并执行第一次计算(时间差) 最后,计算每天的nb连接数

然后,最终查询将显示所需的结果。

这是我提出的查询,使用 Postgresql 开发(您没有精确地确定您的 dbms,但在这里转换应该不是什么大问题):

with init_calendar as (
   -- Prepare date series and count total users
   select generate_series(min(log_in_dates), now(), interval  '1 day') as present_date,
          count(distinct user_id) as nb_users
     from users
),
calendar as (
   -- Add connections' dates for each period from the beginning to current date in calendar
   -- and calculate nb days difference for each of them
   -- Syntax my vary depending dbms used
   select distinct present_date, log_in_dates as last_date,
          extract(day from present_date - log_in_dates) as days_difference,
          nb_users
     from init_calendar
     join users on log_in_dates <= present_date
),
usr_con as (
    -- Identify last user connection's dates according to running date
    -- Tag the line to be counted as no connection
    select c.present_date, c.last_date, c.days_difference, c.nb_users,
           u.user_id, max(log_in_dates) as last_con,
           case when max(log_in_dates) = present_date then 0 else 1 end as to_count
      from calendar c
      join users u on u.log_in_dates <= c.last_date
      group by c.present_date, c.last_date, c.days_difference, c.nb_users, u.user_id
)
select present_date, last_date, days_difference,
       nb_users - sum(to_count) as Num_users_no_log_in
from usr_con
 group by present_date, last_date, days_difference, nb_users
 order by present_date, last_date

请注意,由于您在计算中忘记了 user_id = 3,因此与您自己的预期结果有所不同。 如果你想玩查询,你可以用dbfiddle

【讨论】:

以上是关于sql 时间计算,有以下一个每天的刷卡时间表,求每天上班上了多少个小时的sql 语句的主要内容,如果未能解决你的问题,请参考以下文章

sql语言 怎么求每组最大,就是用group by 分组后,求每组某列最大?

SQL/Hive 查询以计算特定值每天的行数

在 SQL 中的日期之间每天计算用户留存率

用于计算每天特定时间的销售额总和的 SQL

asp.net做考勤系统要用到SQL数据库的job吗

用于计算每天订单总数的 SQL 查询?