我的出勤数据存储如下:
Building | Room | Date | Morning | Evening
------------------------------------------
BuildA A1 1 10 15
BuildA A1 2 20 35
BuildA A1 3 30 15
BuildA A2 1 60 30
BuildA A2 2 30 10
BuildA A2 3 40 20
BuildB B1 1 20 25
BuildB B1 2 10 35
BuildB B1 3 30 10
BuildB B2 1 15 25
BuildB B2 2 25 35
BuildB B2 3 25 15
然后,我需要查看每个房间与前一天的出勤率差异。结果将如下所示:
Building | Room | Date | Morning | Evening | MorningDiff | EveningDiff
-----------------------------------------------------------------------
BuildA A1 1 10 15 0 0
BuildA A1 2 20 35 10 20
BuildA A1 3 30 15 10 -20
BuildA A2 1 60 30 0 0
BuildA A2 2 30 10 -30 -20
BuildA A2 3 40 20 10 10
BuildB B1 1 20 25 0 0
BuildB B1 2 10 35 -10 10
BuildB B1 3 30 10 20 -25
BuildB B2 1 15 25 0 0
BuildB B2 2 25 35 10 10
BuildB B2 3 25 15 0 -20
上一个我能够完成此查询:
select t.*,
COALESCE((`morning` -
(select `morning`
from data t2
where t2.date < t.date
and t2.room = t.room
order by t2.date desc
limit 1 )) ,0)
as MorningDiff,
COALESCE((`evening` -
(select `evening`
from data t2
where t2.date < t.date
and t2.room = t.room
order by t2.date desc
limit 1 )) ,0)
as EveningDiff
from data t
order by room,date asc;
所以现在我的出勤率有所不同。这就是现在变得有点复杂的地方。也许首先看到我想要的最终产品可能会清除它:
Building1 | Room1 | TimeOfDay1 | Direction1 | Building2 | Room2 | TimeOfDay2 | Direction2 | OccuranceCount | Room1DirectionCount | Room2DirectionCount
-----------------------------------------------------------------------------------------------------------------------------------------------------
BuildA A1 Morning Up BuildA A2 Morning Up 1 2 1
BuildA A1 Morning Up BuildA A2 Morning Down 1 2 1
BuildA A1 Morning Up BuildA A2 Evening Up 1 2 1
.
.
.
获得日期之间差异的原因是查看出勤率是否比前一天有所增加。我们实际上并不关心差异的实际数字,我们只是感兴趣它是上升还是下降。
OccuranceCount字段-如果某天某房间的出勤人数增加/减少,我们将尝试查看第二天另一房间的出勤人数是否增加/减少。然后使用此字段来计算room2在一天之内上升/下降以及该room1在第二天上升/下降的次数。因此,如果以第一行为例,则表明room A1
的{{1}}的出席人数上升了morning
的时间1
3天之内的strong>上一个天。
Room1DirectionCount / Room2DirectionCount字段-这些字段仅显示每个房间每个方向发生了多少时间。因此,如果在100天的时间内,如果A1会议室的出席人数增加了60倍,那么计数将是60。
由于我正在相互比较所有房间,因此我尝试进行交叉连接以形成笛卡尔积,但是我一直无法弄清楚如何正确进行连接,因此它引用了另一房间的前一天。 / p>
我不确定为什么将此问题标记为与数据透视表有关的问题的重复项?我不相信这个问题能回答这个问题。
答案 0 :(得分:1)
我很难确定 second 预期输出中某些列的含义。但是,就其价值而言,这里有一些示例和演示可能会对您有所帮助。
如果您正在使用MySQL 8.0,则可以使用精彩的window functions访问与当前行相关的行。以下查询返回您的 first 预期输出(尽管没有以前的日期,但返回NULL
而不是0
,以区别频度相同的情况和前一天一样):
select
a.*,
morning - lag(a.morning) over (partition by a.building, a.room order by a.date) morning_diff,
evening - lag(a.evening) over (partition by a.building, a.room order by a.date) evening_diff
from attendance a
order by a.building, a.room, a.date
对于较早版本的mysql,您可以使用self-LEFT JOIN
访问上一行:
select
a.*,
a.morning - a1.morning morning_diff,
a.evening - a1.evening evening_diff
from
attendance a
left join attendance a1
on a1.building = a.building and a1.room = a.room and a1.date = a.date - 1
order by a.building, a.room, a.date
一旦您有一个返回出勤率差异的查询,就可以轻松地在外部查询中查看它是上升还是下降。考虑例如:
select t.*,
case
when morning_diff is null then 'Unknown'
when morning_diff = 0 then 'Even'
when morning_diff > 0 then 'Up'
when morning_diff < 0 then 'Down'
end morning_direction,
case
when evening_diff is null then 'Unknown'
when evening_diff = 0 then 'Even'
when evening_diff > 0 then 'Up'
when evening_diff < 0 then 'Down'
end evening_direction
from (
select
a.*,
morning - lag(a.morning) over (partition by a.building, a.room order by a.date) morning_diff,
evening - lag(a.evening) over (partition by a.building, a.room order by a.date) evening_diff
from attendance a
) t
order by t.building, t.room, t.date;
请参见this db fiddle。
答案 1 :(得分:1)
我不是100%肯定我理解您的问题,并且确实没有足够的样本数据/预期输出来确定,但是我认为此查询将为您提供所需的结果。它使用了两个CTE:一个用于获取每个建筑物/房间/日期/时间组合的差异,第二个用于对这些差异求和(对于RoomDirectionCount
列),然后仅对分组的行进行计数以获得{{ 1}}列。
OccurrenceCount
输出内容太长,无法包含在此处,但是我创建了demo on dbfiddle。备用demo on dbfiddle.uk
请注意,我使用了with atdiff AS (SELECT
building, room, date, 'Morning' AS time_of_day,
morning - lag(morning) over (partition by building, room order by date) AS diff
from attendance
UNION SELECT
building, room, date, 'Evening',
evening - lag(evening) over (partition by building, room order by date) diff
from attendance),
dircounts AS (SELECT
building, room, time_of_day, SIGN(diff) AS direction, COUNT(*) AS DirectionCount
FROM atdiff
GROUP BY building, room, time_of_day, direction)
select a1.building AS Building1,
a1.room AS Room1,
a1.time_of_day AS TimeOfDay1,
(CASE SIGN(a1.diff) WHEN 1 THEN 'Up' WHEN -1 THEN 'Down' ELSE 'Unchanged' END) AS Direction1,
a2.building AS Building2,
a2.room AS Room2,
a2.time_of_day AS TimeOfDay2,
(CASE SIGN(a2.diff) WHEN 1 THEN 'Up' WHEN -1 THEN 'Down' ELSE 'Unchanged' END) AS Direction2,
COUNT(*) AS OccurrenceCount,
MIN(d1.DirectionCount) AS Room1DirectionCount,
MIN(d2.DirectionCount) AS Room2DirectionCount
from atdiff a1
join atdiff a2 on a2.date = a1.date + 1 AND (a2.building != a1.building OR a2.room != a1.room)
JOIN dircounts d1 ON d1.building = a1.building AND d1.room = a1.room AND d1.time_of_day = a1.time_of_day AND d1.direction = SIGN(a1.diff)
JOIN dircounts d2 ON d2.building = a2.building AND d2.room = a2.room AND d2.time_of_day = a2.time_of_day AND d2.direction = SIGN(a2.diff)
where a1.diff is not NULL
group by Building1, Room1, TimeofDay1, Direction1, Building2, Room2, TimeOfDay2, Direction2
order by Building1, Room1, TimeofDay1 DESC, Direction1 DESC, Building2, Room2, TimeOfDay2 DESC, Direction2 DESC
子句来排除第一天的结果,您可能会在WHERE a1.diff IS NOT NULL
中对COALESCE
的计算中放置一个diff
表,然后不使用它。