[英]Generating complex sql tables
我目前有一个员工记录的SQL表,该表具有3列
fromState: String
, toState: String
, timestamp: DateTime
fromState
是In
或Out
。 In
手段员工进来, Out
意味着员工走了出去。 每行只能从In
到Out
或Out
到In
过渡。
我想在sql中生成一个临时表,以在给定的小时(小时一小时)内跟踪公司中有多少员工。 HourBucket
,结果表具有HourBucket
列, NumEmployees
列。
在非SQL代码中,我可以通过将numEmployees
初始化为0
并逐行遍历表(按timestamp
排序),然后向numEmployees
添加(雇员入职)或减去(出去)(按timestamp
小时numEmployees
)来numEmployees
。
我对如何在SQL中做到这一点一无所知。 有什么线索吗?
使用COUNT ... GROUP BY
查询。 从您的描述中看不到您正在使用toState! 另外,假设您有一个employeeID字段。
例如
SELECT fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable
INNER JOIN (SELECT employeeID AS 'empID', MAX(timestamp) AS 'latest' FROM StaffinBuildingTable GROUP BY employeeID) AS LastEntry ON StaffinBuildingTable.employeeID = LastEntry.empID
GROUP BY fromState
LastEntry子查询将生成一个雇员ID列表,该ID限于每个雇员的最后一个时间戳。
INNER JOIN会将主表限制为仅与双方都匹配的employeeID。
外部GROUP BY产生计数。
SELECT HOUR(SBT.timestamp) AS 'Hour', SBT.fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable AS SBT
INNER JOIN (
SELECT SBIJ.employeeID AS 'empID', MAX(timestamp) AS 'latest'
FROM StaffinBuildingTable AS SBIJ
WHERE DATE(SBIJ.timestamp) = CURDATE()
GROUP BY SBIJ.employeeID) AS LastEntry ON SBT.employeeID = LastEntry.empID
GROUP BY SBT.fromState, HOUR(SBT.timestamp)
用您感兴趣的任何日期替换CURDATE()。
请注意,这不是最佳选择,因为它两次计算HOUR(一次),一次是针对数据,一次是针对组。
再次使用INNER JOIN限制返回的行数,这次是给定日期的最后一个时间戳。
对我来说,您对FromState
和ToState
描述似乎是错误的方式,我希望基于ToState
进行此ToState
。 但是,假设我错了,那么以下内容将为您指明正确的方向:
首先,我创建一个“ Numbers”表,该表包含一天中每小时的24行:
create table tblHours
(Number int);
insert into tblHours values
(0),(1),(2),(3),(4),(5),(6),(7),
(8),(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),(23);
然后,对于您的员工日志表中的每个日期,我在另一个新表中创建一行以包含您的计数:
create table tblDailyHours
(
HourBucket datetime,
NumEmployees int
);
insert into tblDailyHours (HourBucket, NumEmployees)
select distinct
date_add(date(t.timeStamp), interval h.Number HOUR) as HourBucket,
0 as NumEmployees
from
tblEmployeeLogging t
CROSS JOIN tblHours h;
然后,我更新此表以包含所有相关计数:
update tblDailyHours h
join
(select
h2.HourBucket,
sum(case when el.fromState = 'In' then 1 else -1 end) as cnt
from
tblDailyHours h2
join tblEmployeeLogging el on
h2.HourBucket >= el.timeStamp
group by h2.HourBucket
) cnt ON
h.HourBucket = cnt.HourBucket
set NumEmployees = cnt.cnt;
现在,您可以使用
select *
from tblDailyHours
order by HourBucket;
计数会显示每个显示时间的现场电话号码,如果您需要在上述时段内进行调整,则需要进行一些调整。
该代码有一个有效的版本(在日志记录表中使用不太实际的数据): rextester.com/DYOR23344
原始答案 (基于单个总数)
如果您乐于搜索所有行,并希望获得当前的“人数”,则可以使用以下方法:
select
sum(case when t.FromState = 'In' then 1 else -1) as Heads
from
MyTable t
但是,如果您知道在午夜总是没有人,则可以添加一个where子句,以防止它查看的行数超过了所需的行数:
where
date(t.timestamp) = curdate()
同样,假设人员总数在午夜达到零,您可以将这种方法推广为在任何时间获取人员总数,如下所示:
where
date(t.timestamp) = "CENSUS DATE" AND
t.timestamp <= "CENSUS DATETIME"
显然,您需要将我带引号的字符串替换为返回感兴趣的日期和日期时间的代码。 如果人数在午夜没有恢复为零,则可以通过删除where
子句的第一行来实现相同目的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.