addSql(<<<'SQL' WITH ranked AS ( SELECT id, rank() OVER ( PARTITION BY stored_object_id, filename, "key"::jsonb, iv::jsonb ORDER BY id DESC ) AS rn FROM chill_doc.stored_object_version ) DELETE FROM chill_doc.stored_object_version sov USING ranked r WHERE sov.id = r.id AND r.rn > 1 SQL); // 2) Create a partial unique index on filename that applies only to subsequently inserted rows. // Per user's instruction, compute the cutoff using the stored_object_id sequence value. $nextVal = (int) $this->connection->fetchOne("SELECT nextval('chill_doc.stored_object_version_id_seq')"); // Safety: if somehow sequence is not available, fallback to current max id from the table if ($nextVal <= 0) { $nextVal = (int) $this->connection->fetchOne('SELECT COALESCE(MAX(id), 0) FROM chill_doc.stored_object_version'); } $this->addSql(sprintf( 'CREATE UNIQUE INDEX chill_doc_stored_object_version_unique_by_filename ON chill_doc.stored_object_version (filename) WHERE id > %d', $nextVal )); } public function down(Schema $schema): void { // Drop the partial unique index; data cleanup is irreversible. $this->addSql('DROP INDEX IF EXISTS chill_doc_stored_object_version_unique_by_filename'); } }