繁体   English   中英

生成复杂的SQL表

[英]Generating complex sql tables

我目前有一个员工记录的SQL表,该表具有3列

fromState: StringtoState: Stringtimestamp: DateTime

fromStateInOut In手段员工进来, Out意味着员工走了出去。 每行只能从InOutOutIn过渡。

我想在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限制返回的行数,这次是给定日期的最后一个时间戳。

对我来说,您对FromStateToState描述似乎是错误的方式,我希望基于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM