Home > Net >  How to round robin by UUID in SQL database?
How to round robin by UUID in SQL database?

Time:02-07

I have a list of agents that I want to assign tasks to using round robin.

agents table:

id
uuid1
uuid2
uuid3
uuid4

How to get rows of the table above in a round robin fashion?

Desired outcome:

uuid1 -> uuid2 -> uuid3 -> uuid4 -> uuid1 (repeat)

I tried ordering uuids then selecting the next one based on the previous uuid

SELECT id FROM agents ORDER BY id; // When there is no previous

SELECT id FROM agents WHERE id > 'uuid1' ORDER BY id; // After the first query

But I don't know how to repeat when I reach the last uuid (when uuid4 is retrieved and uuid1 must be selected again)

CodePudding user response:

select nxt
from (
  select
    -- for every id, find the next item, if not exists, use the earliest (min) 
    id, coalesce(lead(id) over (order by id),(select min(id) from Tbl)) as nxt 
  from Tbl
  ) as Agents
where id = 'uuid4'

CodePudding user response:

I don't have PostgreSQL handy right now, but this works under SQL Server and I don't see an obvious reason why it shouldn't under any other DBMS:

COALESCE(
    (SELECT TOP 1 id FROM agents WHERE @current_id < id ORDER BY id),
    (SELECT TOP 1 id FROM agents ORDER BY id)
)

So it simply tries to get the next id (the first argument of COALESCE), and if there is no next id gets the first id (the second argument of COALESCE).


Here is a full T-SQL demo, something similar can probably be done under PostgreSQL...

CREATE TABLE agents  (
    id uniqueidentifier PRIMARY KEY
);

INSERT INTO agents VALUES (NEWID()), (NEWID()), (NEWID()), (NEWID());

DECLARE @current_id uniqueidentifier;

DECLARE @i int = 0;
WHILE @i < 10 BEGIN

    SET @current_id = COALESCE(
        (SELECT TOP 1 id FROM agents WHERE @current_id < id ORDER BY id),
        (SELECT TOP 1 id FROM agents ORDER BY id)
    );

    PRINT CONCAT('@current_id = ', @current_id);

    SET @i = @i   1;

END

CodePudding user response:

You can combine two queries where the second is only run if the first one didn't return anything:

with next_agent as (
  SELECT id
  FROM agents 
  WHERE id > $1 -- the last ID retrieved or NULL if it's the first
  ORDER BY id
  limit 1
)
select *
from next_agent
union all
(
  select *
  from agents
  where not exists (select * from next_agent)
  order by id
  limit 1
)

So if $1 is null (first call) or 'uuid4' the next_agent CTE will not return anything. And in that case the second part of the UNION in the outer query will be run picking the "first" row

  •  Tags:  
  • Related