I have
User table[user_id]
Disperse Table [order_id, disperse_amount]
Pool Table [user_id, order_id]
For each order_id in Disperse, I want to insert x random rows of [user.user_id, disperse.order_id] into pool table. (x is the current row’s disperse_amount)
Might be more understandable with the query I have so far:
WITH p as (
SELECT *
FROM pool p
WHERE p.order_id= **disperse.order_id** (from current disperse row)
)
INSERT INTO pool (order_id, user_id)
SELECT **disperse.order_id**, user_id
FROM users
WHERE NOT EXISTS (
SELECT 1
FROM p
WHERE user_id = users.user_id
)
ORDER BY random()
LIMIT **disperse.disperse_amount** (from the current disperse row)
This could work for ONE row in the distributer table.
I just need to iterate through all rows of distributer table [order_id, disperse_amount], and for each row, perform this query.
There may be a much more efficient way to do this, but I wouldn’t know as I’m a novice to postgres and webdev in general.
2
Answers
you can make use of a PL/pgSQL function in PostgreSQL. This solution leverages PostgreSQL’s procedural language to efficiently manage the insertion process with the required logic for random selection and duplication avoidance, offering a straightforward approach to performing bulk, conditional, and randomized data insertion operations within a PostgreSQL database:
Then you can use it like this:
Any time you want to iterate in SQL, there’s a better way.
Here we can use a
cross join lateral
to match up each entry in disbursements with the appropriate random picks from users. A cross join matches every row in a one table with every row in another table.lateral
evaluates the subquery for each row; this allows us to uselimit d.disburse_amount
.What if there are already entries in order_pool? Let’s assume we don’t want to go over the disburse_amount and we don’t want to repeat any user_ids for the same order.
First, we need to know how many disbursements remain for each order.
Then we select from the query above instead of disbursements, and cross join lateral as before with the extra clause to exclude users who are already in the pool. Cross join lateral, as before, lets us do this for each order.
This can safely be run as an insert trigger on the disbursements table to keep the order pool up to date on new disbursements. Deletes and updates must be handled separately.