Depending on how you want to de-duplicate the records, there are a few different ways to accomplish this. The most straightforward is:
SELECT
DISTINCT ON (product_id)
id
, product_id
, url
, is_primary
FROM table
From the documentation:
SELECT DISTINCT eliminates duplicate rows from the result. SELECT DISTINCT ON eliminates rows that match on all the specified expressions. SELECT ALL (the default) will return all candidate rows, including duplicates. (See DISTINCT Clause below.)
It sounds like you'll probably want to use DISTINCT ON instead of DISTINCT; the difference being DISTINCT ON allows you to return columns not part of the distinct component.
If you need to do something more complex (e.g. find the smallest id
associated with the product_id
), you can add sorting to the query which will make the result deterministic by adding an ORDER BY clause.
The thing to note about ORDER BY clauses used in conjunction with DISTINCT ON is that all of the columns in DISTINCT ON must come first in the ORDER BY. So it becomes possible to find the smallest id
associated with each product with something like:
SELECT
DISTINCT ON (product_id)
id
, product_id
, url
, is_primary
FROM table
ORDER BY
product_id
, id ASC
Depending on how this table is set up, there may be an easier answer. If is_primary
is a boolean column with a partial unique index (see this post and this documentation for more details), you'd be able to get a single id
per product_id
with a query like:
SELECT
id
, product_id
, url
, is_primary
FROM table
WHERE is_primary
I mention this because it's a really nice way to filter to a single unique value if your database is set up this way. Depending on your table size, it may also be more performant because Postgres will have an index on disk and won't need to sort through all of the possible records.
If your goal is to actually delete the duplicate records from the table, one way to do it would be to form a query (e.g. one of the above) with the valid records, and then use it as the USING clause for a DELETE statement with a WHERE NOT EXISTS clause.