connection->executeStatement( "ALTER TABLE {$table} ADD entity_type VARCHAR(10) NULL, ADD entity_id INT NULL" ); // Only owners with exactly one environment can be resolved without a guess. $this->connection->executeStatement( "UPDATE {$table} t JOIN (SELECT u.id AS user_id, MAX(d.id) AS doctor_id, MAX(c.id) AS clinic_id, COUNT(DISTINCT d.id) + COUNT(DISTINCT c.id) AS envs FROM users u LEFT JOIN doctors d ON d.user_id = u.id LEFT JOIN clinics c ON c.user_id = u.id GROUP BY u.id) x ON x.user_id = t.user_id SET t.entity_type = IF(x.clinic_id IS NOT NULL, 'clinic', 'doctor'), t.entity_id = IFNULL(x.clinic_id, x.doctor_id) WHERE x.envs = 1" ); $unassigned = (int) $this->connection->fetchOne( "SELECT COUNT(*) FROM {$table} WHERE entity_type IS NULL" ); $this->write(sprintf( ' %s: %d row(s) left without an environment — their owner has more than one and must choose.', $table, $unassigned, )); $this->connection->executeStatement( "CREATE INDEX idx_{$table}_entity ON {$table} (entity_type, entity_id)" ); } } public function down(Schema $schema): void { foreach (self::TABLES as $table) { $this->addSql("DROP INDEX idx_{$table}_entity ON {$table}"); $this->addSql("ALTER TABLE {$table} DROP entity_type, DROP entity_id"); } } /** DDL on MariaDB commits implicitly; wrapping up() in a transaction would be a lie. */ public function isTransactional(): bool { return false; } }