简体   繁体   中英

List events based on date and time

i'm wondering if someone can help me out with this one

I have the following query :

SELECT * FROM `E935308` WHERE date BETWEEN '2015-09-03' AND '2015-09-03' ORDER BY date, time, id

The result would be like this:

date        time    event
2015-09-03  23327   4
2015-09-03  23402   5
2015-09-03  23434   4
2015-09-03  23991   5
2015-09-03  24030   4
2015-09-03  24195   45
2015-09-03  24210   5
2015-09-03  24627   4
2015-09-03  24634   5
2015-09-03  26348   4
2015-09-03  26370   46
2015-09-03  27152   5
2015-09-03  28407   4
2015-09-03  28408   5
2015-09-03  29856   4
2015-09-03  30428   45
2015-09-03  30449   46
2015-09-03  30514   45
2015-09-03  30540   46
2015-09-03  30555   45
2015-09-03  30617   46
2015-09-03  30631   45

There are four events (4, 5, 45 and 46) Assuming that : 4 = START, 5 = STOP, 45 = IN and 46 = OUT

I need an algorithm to show me the time of the very first event number 4, and after that the time of the first 45 after 4 and 46 that comes right after 45 and at last the first 5 after event 46.

Here is a working example:

2015-09-03  23327   24195   26370   27152
2015-09-03  28407   30428   30449   -
2015-09-03  28407   30514   30540   -

the dash means event 5 doesn't exist.

I don't know if this is possible, still worth asking for.

Thanks for the help.

EDIT:

To make it a little bit clear, how to eliminate the numbers that are not in brackets?

[4]
5
4
5
4
[45]
5
4
5
4
[46]
[5]
4
5

EDIT: first solution was wrong.

There could be more elegant solutions, but here with only 4 events you can get it in a single scan with 5 variables.

This solution dies when you have joins, so if so you must encapsulate all the joins and orders in an inner subselect, so that the variables-magic just happens on a clear single ordered stream of data. All the queries must be sent in the same SQL Connection, otherwise you will lose the variables of course.

If you leave out the outer select and just use the inner select, you see that there is no real magic happening, just simple if-then in MySQL.

Additional info, you can even modify this to measure times between In and Out.

The fiddle shows how it works, and fiddle gets the results. In your example you forgot the touple 128407, 30555, 30617, -1

set @found4=0;
set @found5=0;
set @found45=0;
set @found46=0;
set @current45=0;

select first4, current45, first46, max(first5)
  from (
      select `date`, `time`, event, @found4:=if(event=4 and @found4=0, time+@found5 := 0, @found4) as first4, 
      @found45:=if(event=45 and @found4>0 and @found45=0,  time + @found46 := 0, @found45) as first45,
      @found46:=if(event=46 and @found4>0 and @found45>0 and @found46 = 0,  time + (@current45:=@found45) - @found45 + @found45 :=0, @found46) as first46,
      @current45 as current45,
      @found5:=if(event=5 and @found4>0 and @found46 > 0 and @found5 = 0, time + @found4:=0 + @found45 := 0 + @found46 := 0, @found5 ) as first5
      from t0 order by `date`, `time`
      ) as innersel where first4>0 and first46 > 0 group by first4, current45, first46;

This gives

first4  current45   first46     max(first5)
23327   24195       26370       27152
28407   30428       30449       0
28407   30514       30540       0
28407   30555       30617       0

as results.

I hope you see your "state machine" in the setting and resetting of the variables. I must add and subtract @found45 in order to set @current45 , but not to disturb @found46 .

Here is a php solution based on the answer of flaschenpost i know it's not a great one but it's close to what i need. still only one problem.

    $req="SELECT * FROM t0 WHERE date BETWEEN '2015-09-03' AND '2015-09-03' ORDER BY date, time, id";
    $q = $conn->prepare($req);
    $q->execute();

    $event1 = 0;
    $event2 = 0;
    $event3 = 0;
    $event4 = 0;
    while($r=$q->fetch()){

        if($r['event'] == 4 and $event1 == 0) {
            echo $r['time'] . ' - ' . $r['event'] . '<br>';
            $event1 = 1;
            $event2 = 0;
            $event3 = 0;
            $event4 = 0;
        }

        if($r['event'] == 45 and $event1 == 1) {
            echo $r['time'] . ' - ' . $r['event'] . '<br>';
            $event1 = 1;
            $event2 = 1;
            $event3 = 0;
            $event4 = 0;
        }

        if($r['event'] == 46 and $event1 == 1) {
            echo $r['time'] . ' - ' . $r['event'] . '<br>';
            $event1 = 1;
            $event2 = 1;
            $event3 = 1;
            $event4 = 0;
        }

        if($r['event'] == 5 and $event1 == 1 and $event2 == 1 and $event3 == 1) {
            echo $r['time'] . ' - ' . $r['event'] . '<br><br>';
            $event1 = 0;
            $event2 = 0;
            $event3 = 0;
            $event4 = 0;
        }
    }

The result is:

    23327 - 4      -> Start Event 1
    24195 - 45
    26370 - 46
    27152 - 5      -> End Event 1

    28407 - 4      -> Start Event 2
    30428 - 45
    30449 - 46      -> This must be considered the End of Event 2    
    30514 - 45      -> This must be considered the Start of Event 3
    30540 - 46      -> This must be considered the End of Event 3
    30555 - 45
    30617 - 46
    30631 - 45
    30687 - 46
    30723 - 45
    34059 - 46
    34073 - 45
    34479 - 46
    34499 - 5

    34660 - 4
    34665 - 45
    35007 - 46
    35009 - 45
    36505 - 45
    36505 - 46
    36525 - 5

    47085 - 4

As you can see there might be a case where we don't have events 4 and 5 so we must show only events 45 and 46.

Any help is appreciated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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