Итерация по таблице SQL, выполнение запроса для каждой строки, соответствующей критериям - PullRequest
0 голосов
/ 05 июля 2019

Я пытаюсь решить проблему, которая займет таблицу следующим образом:

--- LOG ---
user  time  status
0     001   ARRIVED
0     003   LEFT
0     009   ARRIVED
1     004   ARRIVED
0     012   LEFT
1     008   LEFT

и выполните задачу: Для каждого времени ПРИБЫТИЯ найдите ближайшее ЛЕВОЕ время для каждого пользователя.

user  ARRIVED   LEFT
0     001       003
0     009       012
1     004       008

Однако мне трудно этого достичь.

Я пытаюсь каким-то образом объединить эти два запроса

SELECT * 
FROM (
    SELECT `user`, `time`  FROM LOG
    WHERE `status` = 'ARRIVED'
);

SELECT * 
FROM (
    SELECT `user`, `time`  FROM LOG
    WHERE `status` = 'LEFT' AND `user` = [USER FROM PREVIOUS TABLE] AND `time` >= [TIME FROM PREVIOUS TABLE]
    ORDER BY `time` ASC
    LIMIT 1
);

Ответы [ 3 ]

0 голосов
/ 05 июля 2019

Пожалуйста, попробуйте ниже запроса.

select a.user,a.time as 'ARRIVED',min(b.time) as 'LEFT'
from log a,log b
where a.user=b.user
and a.status='ARRIVED'
and b.status='LEFT'
and a.time<=b.time
group by a.user,a.time

Таблица содержит 6 записей, и при самостоятельном соединении с таблицей будет получено 36 записей, все комбинации, из которых мы можем отфильтровать то, что нам нужно. Ниже приведены фильтры 1) Фильтр на основе пользователя, поскольку мы ищем только конкретные действия пользователя 2) Фильтры, которые нужно сравнить, ПРИБЫТЫ против ЛЕВЫХ 3) В течение любого ЛЕВОГО времени нам нужно искать только прибывшее время до ЛЕВОГО времени, и оно может быть таким же. (A.time <= b.time) * +1004 * 4) Группировка по времени пользователя и времени прибытия предоставит вам список всех ВЛЕВОГО времени, которое больше или равно времени прибытия для любого пользователя. 5) Агрегатор MIN используется, так как мы ищем только самое раннее левое время для данного пользователя прибывшего времени. </p>

0 голосов
/ 05 июля 2019

Вы можете использовать свои запросы без объединения, как это:

select 
  t.user, 
  t.time ARRIVED,
  (select time from log where user = t.user and status = 'LEFT' and time > t.time 
   order by time asc limit 1) `LEFT`    
from log t
where t.status = 'ARRIVED'

См. Демоверсию .
Результаты:

| user | ARRIVED | LEFT |
| ---- | ------- | ---- |
| 0    | 001     | 003  |
| 0    | 009     | 012  |
| 1    | 004     | 008  |
0 голосов
/ 05 июля 2019

Вы можете попробовать что-то вроде этого:

SELECT
      a.`user`
    , a.`time` AS `ARRIVED`
    , l.`time` AS `LEFT`
FROM 
    `LOG` AS a
    INNER JOIN `LOG` AS l ON (
            l.`status` = 'LEFT'
        AND l.`user` = a.`user`
        AND l.`time` > a.`time`
    )
    LEFT JOIN `LOG` AS l_prev ON (
            l_prev.`status` = 'LEFT'
        AND l_prev.`user` = l.`user`
        AND l_prev.`time` < l.`time`
        AND l_prev.`time` > a.`time`
    )
WHERE
        a.`status` = 'ARRIVED'
    AND l_prev.`time` IS NULL
;

=>

user    ARRIVED LEFT
0   1   3
0   9   12
1   4   8

время INT в моем примере

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...