将所有房间与所有其他房间(笛卡尔积)进行比较

时间:2019-01-21 20:23:09

标签: mysql

我的出勤数据存储如下:

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>

我不确定为什么将此问题标记为与数据透视表有关的问题的重复项?我不相信这个问题能回答这个问题。

2 个答案:

答案 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

See the db fiddle

对于较早版本的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

请参见this MySQL 5.7 db fiddle

一旦您有一个返回出勤率差异的查询,就可以轻松地在外部查询中查看它是上升还是下降。考虑例如:

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表,然后不使用它。