Как выбрать первый элемент по группе с условием? - PullRequest
0 голосов
/ 14 июня 2019

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

Sequence | User | Order | InProcess
---------+------+-------+----------
       1 |    1 |     1 |
       2 |    1 |     2 |
       3 |    2 |     1 |
       4 |    3 |     1 |
       5 |    1 |     3 |
       6 |    4 |     1 |
       7 |    2 |     2 |

Например, строка 4 | 3 | 1 | означает, что 4-й ордер когда-либо предназначен для пользователя 3, и это его / ее 1-й ордер. Теперь я хочу выбрать заказ, который будет обрабатываться следующим. Это должно быть сделано в соответствии со следующими критериями:

  • Старые заказы (с меньшими порядковыми номерами) обрабатываются первыми.
  • Одновременно обрабатывается только один заказ.
  • Как только ордер выбран как обрабатываемый, он помечается как InProcess.
  • Как только заказ завершен, он удаляется из этого списка.

Итак, через некоторое время это может выглядеть так:

Sequence | User | Order | InProcess
---------+------+-------+----------
       1 |    1 |     1 | X
       2 |    1 |     2 |
       3 |    2 |     1 | X
       4 |    3 |     1 | X
       5 |    1 |     3 |
       6 |    4 |     1 |
       7 |    2 |     2 |

При запросе следующего заказа на обработку ответом будет строка с порядковым номером 6, поскольку заказы для пользователей 1, 2 и 3 уже обрабатываются, поэтому дополнительный заказ для них обрабатываться не может. Вопрос в том, как мне эффективно добраться до этой строки?

В основном мне нужен SQL-эквивалент

Из всех заказов выберите первый заказ, который не обрабатывается, и у которого пользователь еще не обрабатывал заказ.

Вопрос только в том, как сказать это с помощью SQL? Кстати: я ищу стандартное решение SQL, а не специфические для СУБД пути. Однако, если по какой-либо причине я ограничиваю вопрос конкретной СУБД, я должен поддержать эти (в следующем порядке):

  • PostgreSQL
  • MariaDB
  • MySQL
  • SQL Server
  • MongoDB

Есть идеи?

Ответы [ 2 ]

1 голос
/ 14 июня 2019

Я думаю, захватывает вашу логику:

select t.*
from (select t.*, max(in_process) over (partition by user_id) as any_in_process
      from t
     ) t
where any_in_process is null
order by sequence
fetch first 1 row only;

Выборка одной строки зависит от базы данных, а остальные довольно общие.

0 голосов
/ 14 июня 2019

Вы можете получить следующий заказ для обработки с помощью оконной функции ROW_NUMBER(), например:

select * 
from (
  select
    *,
    row_number() over(order by "order", "sequence") as as rn
  from t
  where "user" not in (
    select "user" from t where inprocess = 'X'
  )
) x 
where rn = 1

Доступно в PostgreSQL, MariaDB 10.2, MySQL 8.0, SQL Server 2012.

...