@@ -450,6 +450,89 @@ within your seed class and then use the ``insert()`` method to insert data:
450450 You must call the ``saveData() `` method to commit your data to the table.
451451 Migrations will buffer data until you do so.
452452
453+ Insert Modes
454+ ============
455+
456+ In addition to the standard ``insert() `` method, Migrations provides specialized
457+ insert methods for handling conflicts with existing data.
458+
459+ Insert or Skip
460+ --------------
461+
462+ The ``insertOrSkip() `` method inserts rows but silently skips any that would
463+ violate a unique constraint:
464+
465+ .. code-block :: php
466+
467+ <?php
468+
469+ use Migrations\BaseSeed;
470+
471+ class CurrencySeed extends BaseSeed
472+ {
473+ public function run(): void
474+ {
475+ $data = [
476+ ['code' => 'USD', 'name' => 'US Dollar'],
477+ ['code' => 'EUR', 'name' => 'Euro'],
478+ ];
479+
480+ $this->table('currencies')
481+ ->insertOrSkip($data)
482+ ->saveData();
483+ }
484+ }
485+
486+ Insert or Update (Upsert)
487+ -------------------------
488+
489+ The ``insertOrUpdate() `` method performs an "upsert" operation - inserting new
490+ rows and updating existing rows that conflict on unique columns:
491+
492+ .. code-block :: php
493+
494+ <?php
495+
496+ use Migrations\BaseSeed;
497+
498+ class ExchangeRateSeed extends BaseSeed
499+ {
500+ public function run(): void
501+ {
502+ $data = [
503+ ['code' => 'USD', 'rate' => 1.0000],
504+ ['code' => 'EUR', 'rate' => 0.9234],
505+ ];
506+
507+ $this->table('exchange_rates')
508+ ->insertOrUpdate($data, ['rate'], ['code'])
509+ ->saveData();
510+ }
511+ }
512+
513+ The method takes three arguments:
514+
515+ - ``$data ``: The rows to insert (same format as ``insert() ``)
516+ - ``$updateColumns ``: Which columns to update when a conflict occurs
517+ - ``$conflictColumns ``: Which columns define uniqueness (must have a unique index)
518+
519+ .. warning ::
520+
521+ Database-specific behavior differences:
522+
523+ **MySQL **: Uses ``ON DUPLICATE KEY UPDATE ``. The ``$conflictColumns `` parameter
524+ is ignored because MySQL automatically applies the update to *all * unique
525+ constraint violations on the table. Passing ``$conflictColumns `` will trigger
526+ a warning. If your table has multiple unique constraints, be aware that a
527+ conflict on *any * of them will trigger the update.
528+
529+ **PostgreSQL/SQLite **: Uses ``ON CONFLICT (...) DO UPDATE SET ``. The
530+ ``$conflictColumns `` parameter is required and specifies exactly which unique
531+ constraint should trigger the update. A ``RuntimeException `` will be thrown
532+ if this parameter is empty.
533+
534+ **SQL Server **: Not currently supported. Use separate insert/update logic.
535+
453536Truncating Tables
454537=================
455538
0 commit comments