【问题标题】:sql server get min time?sql server 获取最小时间?
【发布时间】:2012-12-21 00:46:24
【问题描述】:

问题来了,

我有一个名为 attendance 的表,有 4 列:

[Username] varchar(256)
[Date] varchar(256)
[Time] varchar(256)
[Action] varchar(256)

我希望实现的是获得第一次入住和退房时间和最后一次入住和退房时间。如果表中只有一个签入和签出行,则返回相同。

这样的示例数据:

Username | Date       | Time     | Action
--------------------------------------------
User1    | 01/12/2012 | 12:54:41 | Check In
User1    | 01/12/2012 | 18:26:36 | Check Out
User1    | 01/12/2012 | 18:44:17 | Check In
User1    | 01/12/2012 | 22:05:31 | Check Out

我的预期结果如下所示:

Output:
Username | Date       | First In | First Out | Last In  | Last Out
User1    | 01/12/2012 | 12:54:41 | 18:26:36  | 18:44:17 | 22:05:31

我尝试了这条 SQL 语句:

SELECT [USERNAME], [DATE]
, min(case when [action] = 'Clock In' then [time] else '' end) as 'First in'
, min(case when [action] = 'Clock Out' then [time] else '' end )as 'First out'
, max(case when [action] = 'Clock In' then [time] else '' end) as 'Last in'
, max(case when [action] = 'Clock Out' then [time] else '' end )as 'Last out'
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012'
group by [username],[date]

它返回意外的结果,即我的最小值总是 '' 或为空,但我的最大值都是 “后进”和“后出”的值正确。

Output:
Username | Date       | First In | First Out | Last In  | Last Out
User1    | 01/12/2012 |          |           | 18:44:17 | 22:05:31

我的 SQL 有什么问题吗?

谁能给点建议?

【问题讨论】:

  • 将日期和时间存储为 DateTime?
  • @TonyHopkinson Nope..both in varchar(256)
  • 我认为 Tony 的评论是对改进数据库的一种方法的建议 - 您确实应该使用适当的日期类型来存储值,而不是使所有内容 varchar(256)。除非您认为'the day after my birthday'(例如)是一个适合存储在Date 列中的值。
  • 阅读(并关注!)这个:Bad habits to kick - using the wrong datatypes
  • @marc_s 表示感谢,这是一篇不错的文章。

标签: sql sql-server-2008 datetime max min


【解决方案1】:

我会使用 row_number() 来做这件事略有不同:

select username, date,
  max(case when [action] = 'Check In' and rn=1 then time end) FirstIn,
  max(case when [action] = 'Check Out' and rn=1 then time end) FirstOut,
  max(case when [action] = 'Check In' and rn=2 then time end) LastIn,
  max(case when [action] = 'Check Out' and rn=2 then time end) LastOut
from
(
  select username, cast(date as date) date, 
    cast(time as time) time, 
    action,
    row_number() 
      over(partition by username, cast(date as date), action
           order by cast(time as time)) rn
  from attendance
) src
group by username, date;

SQL Fiddle with Demo

结果是:

| USERNAME |       DATE |          FIRSTIN |         FIRSTOUT |           LASTIN |          LASTOUT |
-----------------------------------------------------------------------------------------------------
|    User1 | 2012-01-12 | 12:54:41.0000000 | 18:26:36.0000000 | 18:44:17.0000000 | 22:05:31.0000000 |

我强烈建议您将datetime 存储为datetime 数据类型。

注意:我将值从 Clock In/Clock Out 更改为 Check In/Check Out 以匹配您提供的示例数据。

【讨论】:

  • 感谢@bluefeet,它也是一个很好的解决方案。但我认为这对我这样的新手来说有点困难..顺便说一句,Sql fiddle 很好......在你告诉我之前就知道了。
  • @LiangCk row_number() over(partition by) 根据您的数据生成一个序号。基本上,查询是说如果usernamedateaction 相同,则仅对数字进行排序。如果是,则增加数量,如果不是,则从新序列开始。 row_number() 对这些类型的查询很有帮助。
【解决方案2】:

试试这个:

SELECT [USERNAME], [DATE]
, min(case when [action] = 'Clock In' then [time]  end) as 'First in'
, min(case when [action] = 'Clock Out' then [time] end )as 'First out'
, max(case when [action] = 'Clock In' then [time] end) as 'Last in'
, max(case when [action] = 'Clock Out' then [time] end )as 'Last out'
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012'
group by [username],[date]

你知道问题出在哪里吗?

【讨论】:

  • 不是很明白,''如果没有值是不是有问题?
  • 您能详细解释一下吗?为什么我不能用'else''”?
  • 空字符串小于任何字符串,因此 min 总是返回空字符串
  • 嗨@Hamlet Hakobyan,如果值返回null怎么办?我可以这样写吗? IsNull(min(case when [action] = 'Clock Out' then [time] end),'' )as 'First out'
  • 已测试,IsNull(min(case when [action] = 'Clock Out' then [time] end),'' )as 'First out' 没有问题
【解决方案3】:

我的解决方案是创建一个存储过程:

DECLARE @first_in VARCHAR, @first_out VARCHAR, @last_in VARCHAR, @last_out VARCHAR
BEGIN
SELECT TOP 1
     @first_in = time
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012' AND [ACTION] = 'first in'
ORDER BY time ASC


SELECT TOP 1
     @first_in = time
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012' AND [ACTION] = 'first out'
ORDER BY time ASC

SELECT TOP 1
     @last_in = time
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012' AND [ACTION] = 'first in'
ORDER BY time DESC

SELECT TOP 1
     @last_out = time
FROM attendance
WHERE [USERNAME] = 'User1' AND [DATE] = '01/12/2012' AND [ACTION] = 'first out'
ORDER BY time DESC

SELECT 'User1','01/12/2012', @first_in, @first_out, @last_in, @last_out
END

【讨论】:

  • 我在更改 Sql 之前使用了这个,我的同事关心的是性能问题。无论如何,执行 4 个 select 语句并不比 1 个 select 语句好。谢谢你的建议。
猜你喜欢
  • 1970-01-01
  • 2016-11-13
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
相关资源
最近更新 更多