pricebook_v1 and pricebook_v2 (product_id, name, category, price) are two releases of a price list exported by a vendor system. The export has no key: a bad load can repeat a row exactly, and any of name, category and price can be NULL.
A downstream copy holds v1 and can only delete whole rows or insert whole rows. Produce the smallest change set that turns v1 into v2 when each release is treated as a bag of rows: for every distinct row, delete the copies v1 has beyond v2's count, and insert the copies v2 has beyond v1's. Two NULLs in the same column count as the same value.
Return one row per operation and distinct row: op ('delete' or 'insert'), the four columns, and copies (how many copies of that row to delete or insert).
Columns: op, product_id, name, category, price, copies. Sort by op, product_id, name, category, price, with NULLs last.