Assigning book ids to certain students on registration of a new student I have a function where I am trying to assign book ids to certain students on registration of a new student.

FOR book_id IN
   SELECT a.bookid
   FROM  books a
   WHERE  a.isdelete = false and published = true

LOOP
IF NOT EXISTS (select 1 from studentbooks where  bookid = book_id and  studentid = id) THEN
     INSERT INTO studentbooks(bookid, studentid) values (book_id::uuid, id );
END IF;

END LOOP;


I wrote something like this and it works fine for smaller set of data and under performs when we have more books to loop through. I just wanted a have a review here.
Instead of extracting all books and execute a separate sub-query on each FOR loop iteration - we can select only the books that don't have matches in studentbooks table for specified student (presented by id argument) by running PostgreSQL LEFT JOIN with specific WHERE clause.

Furthermore, to make it one-shot action - we can insert data from query using INSERT INTO SELECT statement.

The query for the whole task:

INSERT INTO
   studentbooks(bookid, studentid) 
   SELECT
      b.bookid, your_function_name.id 
   FROM
      books b 
      LEFT JOIN
         studentbooks sb 
         ON sb.bookid = b.bookid AND studentid = id 
   WHERE
      b.isdelete = false AND b.published = true
      AND sb.bookid is NULL;


replace your_function_name with your actual function name to refer the function's argument name.