マイグレーション
データベースの表を作ったり変えたりする手順書「マイグレーション」の作り方・動かし方・戻し方と、カラムの型・修飾子・インデックス・外部キーの一覧を説明します。
マイグレーションは、データベースの表の形を、ファイルに書いて残しておく手順書です。プログラムの変更をバージョン管理(変更の履歴を残すしくみ)するのと同じように、データベースの形の変更も、みんなで共有できます。「プログラムを更新したら、自分のデータベースにも、このカラムを足してね」と仲間に頼む必要がなくなります。
Laravel の Schema ファサード(Schema::create() のように、クラス名と :: で機能を呼べる窓口)は、対応しているどのデータベースでも、同じ書き方で表を作ったり変えたりできます。マイグレーションでは、ふつうこの Schema を使って、表やカラムを作ったり変えたりします。
マイグレーションを作る#
make:migration という Artisan コマンド(php artisan で動かす Laravel のコマンド)で、マイグレーションのファイルを作ります。ファイルは database/migrations に置かれます。ファイル名には日時が入っていて、Laravel はそれで動かす順番を決めます。
php artisan make:migration create_flights_table
Laravel は、マイグレーションの名前から、表の名前と、新しい表を作るかどうかを推測します。表の名前が分かれば、作られたファイルにその表の名前を入れておいてくれます。分からないときは、ファイルの中に自分で書きます。
作るファイルの置き場所を変えたいときは、--path オプションに、アプリの一番上のフォルダからの道すじを渡します。
補足
マイグレーションのひな形(stub)は、書き換えて使えます。方法は Artisan コマンドのページにあります。
マイグレーションをまとめる(スカッシュ)#
アプリを作り進めると、マイグレーションが増え続けて、database/migrations が何百ものファイルでいっぱいになることがあります。そのときは、1つの SQL ファイルにまとめられます。schema:dump コマンドを使います。
php artisan schema:dump
# Dump the current database schema and prune all existing migrations...
php artisan schema:dump --prune
動かすと、Laravel は「スキーマ」(表の作りの全体)のファイルを database/schema に書き出します。ファイルの名前は、データベースの接続の名前になります。そのあと、マイグレーションをまだ1つも動かしていないデータベースで migrate すると、Laravel はまずこのスキーマファイルの SQL を動かします。続けて、まとめに入っていない残りのマイグレーションを動かします。
テストが、ふだんの開発とは別のデータベース接続を使うなら、その接続でも、スキーマファイルを作っておく必要があります。そうしないと、テストがデータベースを作れません。ふだんの接続のあとに、続けて作るとよいでしょう。
php artisan schema:dump
php artisan schema:dump --database=testing --prune
チームの新しい人が、すばやく最初のデータベースを作れるように、スキーマファイルはバージョン管理に入れておきます。
注意
マイグレーションのスカッシュに対応しているのは、MariaDB、MySQL、PostgreSQL、SQLite だけです。データベースに付いている、ターミナルで使う道具(コマンドラインのクライアント)を使って動きます。
マイグレーションの形#
マイグレーションのクラスには、up と down の2つのメソッドがあります。up は、表・カラム・インデックスを新しく足すためのもの、down は、up でしたことを元に戻すためのものです。
どちらも、Laravel のスキーマビルダ(Schema で表の形を組み立てるしくみ)を使って、表の作り方や変え方を書きます。Schema ビルダで使えるメソッドは、このページの後ろで説明します。たとえば、次のマイグレーションは flights という表を作ります。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::drop('flights');
}
};
使うデータベース接続を決める#
アプリの既定とは別のデータベース接続を、マイグレーションが使うときは、マイグレーションの $connection プロパティ(クラスの中の変数)に、その接続の名前を入れます。
/**
* The database connection that should be used by the migration.
*
* @var string
*/
protected $connection = 'pgsql';
/**
* Run the migrations.
*/
public function up(): void
{
// ...
}
マイグレーションを飛ばす#
まだ有効にしていない機能のためのマイグレーションなど、いまは動かしたくないものがあります。そのときは、マイグレーションに shouldRun メソッドを書きます。false を返すと、そのマイグレーションは飛ばされます。
use App\Models\Flight;
use Laravel\Pennant\Feature;
/**
* Determine if this migration should run.
*/
public function shouldRun(): bool
{
return Feature::active(Flight::class);
}
マイグレーションを動かす#
まだ動かしていないマイグレーションを全部動かすには、migrate コマンドを使います。
php artisan migrate
動かした分と、まだの分を見たいときは、migrate:status を使います。
php artisan migrate:status
migrate に --step を付けると、マイグレーションを1つずつ別の「バッチ」(ひとまとまり)として動かします。あとで migrate:rollback で、1つずつ戻せます。
php artisan migrate --step
動かさずに、動かす SQL だけを見たいときは、--pretend を付けます。
php artisan migrate --pretend
動かすのを1か所だけにする#
何台かのサーバーに公開していて、公開の手順の中で migrate を動かすなら、2台が同時にデータベースを変えようとするのは避けたいはずです。migrate に --isolated を付けます。
--isolated を付けると、Laravel はマイグレーションを動かす前に、鍵(アトミックなロック。途中で割り込まれない鍵)を1つ取ります。鍵の置き場所には、アプリのキャッシュドライバ(キャッシュのしまい方)を使います。鍵がふさがっている間は、ほかから migrate を動かしても、何もしません。ただし、コマンドは「成功」の終了コード(コマンドが終わるときに返す番号)で終わります。
php artisan migrate --isolated
注意
この機能を使うには、アプリの既定のキャッシュドライバが、memcached、redis、dynamodb、database、file、array のどれかである必要があります。また、すべてのサーバーが、同じ1つのキャッシュサーバーを使っている必要があります。
本番で無理やり動かす#
マイグレーションには、データが消えるかもしれない、危ない操作があります。本番のデータベースで、うっかり動かさないように、動かす前に確認を聞かれます。確認なしで動かすには、--force を付けます。
php artisan migrate --force
マイグレーションを戻す#
直前のマイグレーションを戻すには、rollback コマンドを使います。最後の「バッチ」を戻します。1つのバッチには、複数のマイグレーションのファイルが入っていることがあります。
php artisan migrate:rollback
step オプションで、戻す数を決められます。たとえば、次は最後の5つを戻します。
php artisan migrate:rollback --step=5
batch オプションで、特定のバッチを戻せます。数字は、アプリの migrations 表の batch の値です。たとえば、次はバッチ3の全部を戻します。
php artisan migrate:rollback --batch=3
migrate:rollback にも --pretend があり、動かさずに SQL だけを見られます。
php artisan migrate:rollback --pretend
migrate:reset は、アプリの全部のマイグレーションを戻します。
php artisan migrate:reset
マイグレーション関係のコマンドは、次のとおりです。
| コマンド | 働き |
|---|---|
migrate |
まだ動かしていないマイグレーションを全部動かす |
migrate:status |
動かした分とまだの分を見る |
migrate:rollback |
最後のバッチを戻す |
migrate:reset |
全部のマイグレーションを戻す |
migrate:refresh |
全部戻してから、もう一度動かす |
migrate:fresh |
全部の表を消してから、もう一度動かす |
schema:dump |
表の形を SQL ファイルにまとめる |
| オプション | 働き |
|---|---|
--step |
1つずつ別のバッチとして動かす(rollback と refresh では戻す数を決める) |
--pretend |
動かさずに SQL だけを見る |
--isolated |
ロックを取って、動かすのを1か所だけにする |
--force |
本番でも確認なしで動かす |
--batch |
戻すバッチの番号を決める |
--seed |
動かしたあとに、最初のデータも入れる |
--database |
使うデータベース接続を決める |
--prune |
schema:dump のあとに、いまのマイグレーションのファイルを消す |
戻してもう一度動かす#
migrate:refresh は、全部のマイグレーションを戻してから、migrate を動かします。データベース全体を、作り直すのと同じです。
php artisan migrate:refresh
# Refresh the database and run all database seeds...
php artisan migrate:refresh --seed
step で、戻して動かし直す数を決められます。たとえば、最後の5つを戻して、動かし直します。
php artisan migrate:refresh --step=5
全部の表を消して動かす#
migrate:fresh は、データベースの全部の表を消してから、migrate を動かします。
php artisan migrate:fresh
php artisan migrate:fresh --seed
migrate:fresh は、既定では、既定のデータベース接続の表だけを消します。別の接続にしたいときは、--database に、接続の名前を渡します。名前は、アプリの database の設定ファイルに書いてある接続のものです。
php artisan migrate:fresh --database=admin
注意
migrate:fresh は、表の名前の接頭辞(prefix)に関係なく、全部の表を消します。ほかのアプリと共有しているデータベースで開発しているときは、気をつけて使ってください。
表#
表を作る#
新しい表を作るには、Schema の create を使います。引数は2つで、表の名前と、Blueprint(表の設計図)を受け取るクロージャ(名前のない関数)です。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});
表を作るとき、スキーマビルダのカラムのメソッドは、どれでも使えます。
表やカラムがあるか調べる#
表・カラム・インデックスがあるかは、hasTable・hasColumn・hasIndex で調べられます。
if (Schema::hasTable('users')) {
// The "users" table exists...
}
if (Schema::hasColumn('users', 'email')) {
// The "users" table exists and has an "email" column...
}
if (Schema::hasIndex('users', ['email'], 'unique')) {
// The "users" table exists and has a unique index on the "email" column...
}
接続と表のオプション#
アプリの既定でないデータベース接続で操作するときは、connection を使います。
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});
表を作るときの、ほかの設定をするメソッドもあります。
| メソッド | 働き |
|---|---|
engine |
表のストレージエンジン(データのしまい方)を決める(MariaDB / MySQL) |
charset |
表の文字コードを決める(MariaDB / MySQL) |
collation |
表の照合順序(文字の並べ方の決まり)を決める(MariaDB / MySQL) |
temporary |
一時的な表にする |
comment |
表にコメントを付ける(MariaDB / MySQL / PostgreSQL) |
Schema::create('users', function (Blueprint $table) {
$table->engine('InnoDB');
// ...
});
Schema::create('users', function (Blueprint $table) {
$table->charset('utf8mb4');
$table->collation('utf8mb4_unicode_ci');
// ...
});
temporary を使うと、表は「一時的」になります。一時的な表は、いまのデータベース接続からだけ見えて、接続を閉じると自動で消えます。
Schema::create('calculations', function (Blueprint $table) {
$table->temporary();
// ...
});
Schema::create('calculations', function (Blueprint $table) {
$table->comment('Business calculations');
// ...
});
表を変える#
すでにある表を変えるには、Schema の table を使います。create と同じく、引数は表の名前と、Blueprint を受け取るクロージャです。カラムやインデックスを足せます。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
表の名前を変える・消す#
表の名前を変えるには、rename を使います。
use Illuminate\Support\Facades\Schema;
Schema::rename($from, $to);
表を消すには、drop か dropIfExists を使います。dropIfExists は、あるときだけ消します。
Schema::drop('users');
Schema::dropIfExists('users');
注意
表の名前を変える前に、その表の外部キー制約(表どうしのつながりの決まり)に、マイグレーションの中で、はっきり名前を付けておいてください。Laravel が決まりに沿って付けた名前のままだと、外部キーの名前が、古い表の名前を指したままになります。
カラム#
カラムを作る#
すでにある表にカラムを足すには、Schema::table を使います。Blueprint を受け取るクロージャの中で、カラムを足します。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
カラムの型の一覧#
スキーマビルダの Blueprint には、データベースに足せるカラムの型ごとに、メソッドがあります。下の表に、全部を並べます。「〜相当」は、そのデータベースの型にあたるという意味です。
真偽値(はい・いいえ)#
| メソッド | 説明 |
|---|---|
boolean |
BOOLEAN 相当のカラムを作る |
$table->boolean('confirmed');
文字・文章#
| メソッド | 説明 |
|---|---|
char |
長さを決めた CHAR 相当のカラム |
longText |
LONGTEXT 相当のカラム |
mediumText |
MEDIUMTEXT 相当のカラム |
string |
長さを決めた VARCHAR 相当のカラム |
text |
TEXT 相当のカラム |
tinyText |
TINYTEXT 相当のカラム |
$table->char('name', length: 100);
$table->string('name', length: 100);
$table->text('description');
$table->mediumText('description');
$table->longText('description');
$table->tinyText('notes');
MySQL と MariaDB では、text の仲間に binary の文字コードを付けると、BLOB の仲間のカラムになります。
| 書き方 | できるカラム |
|---|---|
text('data')->charset('binary') |
BLOB |
mediumText('data')->charset('binary') |
MEDIUMBLOB |
longText('data')->charset('binary') |
LONGBLOB |
tinyText('data')->charset('binary') |
TINYBLOB |
$table->text('data')->charset('binary'); // BLOB
$table->mediumText('data')->charset('binary'); // MEDIUMBLOB
$table->longText('data')->charset('binary'); // LONGBLOB
$table->tinyText('data')->charset('binary'); // TINYBLOB
数#
| メソッド | 説明 |
|---|---|
bigIncrements |
自動で増える UNSIGNED BIGINT 相当の主キーのカラム |
bigInteger |
BIGINT 相当のカラム |
decimal |
全体の桁数と小数の桁数を決めた DECIMAL 相当のカラム |
double |
DOUBLE 相当のカラム |
float |
精度を決めた FLOAT 相当のカラム |
id |
bigIncrements の別名。既定のカラム名は id |
increments |
自動で増える UNSIGNED INTEGER 相当の主キーのカラム |
integer |
INTEGER 相当のカラム |
mediumIncrements |
自動で増える UNSIGNED MEDIUMINT 相当の主キーのカラム |
mediumInteger |
MEDIUMINT 相当のカラム |
smallIncrements |
自動で増える UNSIGNED SMALLINT 相当の主キーのカラム |
smallInteger |
SMALLINT 相当のカラム |
tinyIncrements |
自動で増える UNSIGNED TINYINT 相当の主キーのカラム |
tinyInteger |
TINYINT 相当のカラム |
unsignedBigInteger |
UNSIGNED BIGINT 相当のカラム |
unsignedInteger |
UNSIGNED INTEGER 相当のカラム |
unsignedMediumInteger |
UNSIGNED MEDIUMINT 相当のカラム |
unsignedSmallInteger |
UNSIGNED SMALLINT 相当のカラム |
unsignedTinyInteger |
UNSIGNED TINYINT 相当のカラム |
$table->id();
$table->bigIncrements('id');
$table->increments('id');
$table->mediumIncrements('id');
$table->smallIncrements('id');
$table->tinyIncrements('id');
$table->bigInteger('votes');
$table->integer('votes');
$table->mediumInteger('votes');
$table->smallInteger('votes');
$table->tinyInteger('votes');
$table->unsignedBigInteger('votes');
$table->unsignedInteger('votes');
$table->unsignedMediumInteger('votes');
$table->unsignedSmallInteger('votes');
$table->unsignedTinyInteger('votes');
$table->decimal('amount', total: 8, places: 2);
$table->double('amount');
$table->float('amount', precision: 53);
id は、カラム名を渡せば、id 以外の名前にもできます。
日付・時刻#
| メソッド | 説明 |
|---|---|
dateTime |
小数点以下の秒の精度を選べる DATETIME 相当のカラム |
dateTimeTz |
タイムゾーン付きの DATETIME 相当のカラム(精度を選べる) |
date |
DATE 相当のカラム |
time |
精度を選べる TIME 相当のカラム |
timeTz |
タイムゾーン付きの TIME 相当のカラム(精度を選べる) |
timestamp |
精度を選べる TIMESTAMP 相当のカラム |
timestampTz |
タイムゾーン付きの TIMESTAMP 相当のカラム(精度を選べる) |
timestamps |
created_at と updated_at の TIMESTAMP 相当のカラムを作る(精度を選べる) |
timestampsTz |
タイムゾーン付きで、created_at と updated_at を作る(精度を選べる) |
softDeletes |
Eloquent の「ソフト削除」(消さずに印を付ける)に使う、空でもよい deleted_at の TIMESTAMP 相当のカラム |
softDeletesTz |
タイムゾーン付きの softDeletes |
year |
YEAR 相当のカラム |
$table->dateTime('created_at', precision: 0);
$table->dateTimeTz('created_at', precision: 0);
$table->date('created_at');
$table->time('sunrise', precision: 0);
$table->timeTz('sunrise', precision: 0);
$table->timestamp('added_at', precision: 0);
$table->timestampTz('added_at', precision: 0);
$table->timestamps(precision: 0);
$table->timestampsTz(precision: 0);
$table->softDeletes('deleted_at', precision: 0);
$table->softDeletesTz('deleted_at', precision: 0);
$table->year('birth_year');
バイナリ(そのままのデータ)#
| メソッド | 説明 |
|---|---|
binary |
BLOB 相当のカラム |
$table->binary('photo');
MySQL・MariaDB・SQL Server では、length と fixed を渡すと、VARBINARY か BINARY 相当のカラムになります。
$table->binary('data', length: 16); // VARBINARY(16)
$table->binary('data', length: 16, fixed: true); // BINARY(16)
JSON#
| メソッド | 説明 |
|---|---|
json |
JSON 相当のカラム |
jsonb |
JSONB 相当のカラム |
$table->json('options');
$table->jsonb('options');
SQLite では、どちらも TEXT のカラムになります。
UUID と ULID#
UUID と ULID は、重ならないように作る長い ID の種類です。
| メソッド | 説明 |
|---|---|
ulid |
ULID 相当のカラム |
uuid |
UUID 相当のカラム |
ulidMorphs |
{カラム名}_type(VARCHAR)と {カラム名}_id(CHAR(26))の2つを足す |
uuidMorphs |
{カラム名}_type(VARCHAR)と {カラム名}_id(CHAR(36))の2つを足す |
nullableUlidMorphs |
ulidMorphs と同じで、空でもよいカラムになる |
nullableUuidMorphs |
uuidMorphs と同じで、空でもよいカラムになる |
$table->ulid('id');
$table->uuid('id');
$table->ulidMorphs('taggable');
$table->uuidMorphs('taggable');
$table->nullableUlidMorphs('taggable');
$table->nullableUuidMorphs('taggable');
ulidMorphs と uuidMorphs は、ULID や UUID の ID を使う、ポリモーフィックなリレーション(1つの表が、いろいろな表につながるしくみ)のために、必要なカラムをまとめて足す便利なメソッドです。上の例では、taggable_type と taggable_id ができます。
位置のデータ(空間)#
| メソッド | 説明 |
|---|---|
geography |
空間の種類と SRID(空間参照系の ID)を決めた GEOGRAPHY 相当のカラム |
geometry |
空間の種類と SRID を決めた GEOMETRY 相当のカラム |
$table->geography('coordinates', subtype: 'point', srid: 4326);
$table->geometry('positions', subtype: 'point', srid: 0);
補足
空間の型に対応しているかは、データベースのドライバによります。データベースの説明書を見てください。PostgreSQL を使うなら、geography や geometry を使う前に、PostGIS という拡張を入れる必要があります。
表どうしのつながり#
| メソッド | 説明 |
|---|---|
foreignId |
UNSIGNED BIGINT 相当のカラム |
foreignIdFor |
モデルのクラスに合わせた {カラム名}_id を足す。型はモデルのキーによって UNSIGNED BIGINT・CHAR(36)・CHAR(26) のどれか |
foreignUlid |
ULID 相当のカラム |
foreignUuid |
UUID 相当のカラム |
foreignUuidFor |
モデルのクラスに合わせた、UUID の {カラム名}_id を足す |
morphs |
{カラム名}_type(VARCHAR)と {カラム名}_id を足す。_id の型は、モデルのキーによって UNSIGNED BIGINT・CHAR(36)・CHAR(26) のどれか |
nullableMorphs |
morphs と同じで、空でもよいカラムになる |
$table->foreignId('user_id');
$table->foreignIdFor(User::class);
$table->foreignUlid('user_id');
$table->foreignUuid('user_id');
$table->foreignUuidFor(User::class);
$table->morphs('taggable');
$table->nullableMorphs('taggable');
morphs も、ポリモーフィックなリレーションのためのカラムを足す便利なメソッドです。上の例では、taggable_type と taggable_id ができます。
そのほかの型#
| メソッド | 説明 |
|---|---|
enum |
決めた値だけを入れられる ENUM 相当のカラム |
set |
決めた値の組を入れられる SET 相当のカラム |
macAddress |
MAC アドレス(機器の番号)用のカラム。PostgreSQL には専用の型があり、ほかは文字のカラム |
ipAddress |
VARCHAR 相当のカラム。PostgreSQL では INET のカラム |
rememberToken |
「ログインしたままにする」トークン用の、空でもよい VARCHAR(100) 相当のカラム |
vector |
vector 相当のカラム |
$table->enum('difficulty', ['easy', 'hard']);
$table->set('flavors', ['strawberry', 'vanilla']);
$table->macAddress('device');
$table->ipAddress('visitor');
$table->rememberToken();
enum には、許す値を手で書く代わりに、Enum::cases() も使えます。
use App\Enums\Difficulty;
$table->enum('difficulty', Difficulty::cases());
vector は、ベクトル(意味を数の並びにしたもの)を入れるカラムです。
$table->vector('embedding', dimensions: 1536);
ベクトルのカラムに対応しているのは、pgvector 拡張を使った PostgreSQL と、MariaDB 11.7 以上です。PostgreSQL では、vector のカラムを作る前に、pgvector を読み込んでおく必要があります。
Schema::ensureVectorExtensionExists();
ベクトルの近さで探す問い合わせを速くするために、そのカラムにベクトルのインデックスを足せます。vector のカラムで index を呼ぶと、コサイン距離(向きの近さ)を使うベクトルのインデックスができます。
$table->vector('embedding', dimensions: 1536)->index();
カラムの修飾子#
カラムを足すとき、上の型のほかに、いろいろな「修飾子」を付けられます。たとえば、カラムを「空でもよい」にするには、nullable を使います。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
使える修飾子は次のとおりです。インデックスの修飾子は含みません。
| 修飾子 | 説明 |
|---|---|
->after('column') |
別のカラムの「あと」に置く(MariaDB / MySQL) |
->autoIncrement() |
INTEGER のカラムを、自動で増える主キーにする |
->charset('utf8mb4') |
カラムの文字コードを決める(MariaDB / MySQL) |
->collation('utf8mb4_unicode_ci') |
カラムの照合順序を決める |
->comment('my comment') |
カラムにコメントを付ける(MariaDB / MySQL / PostgreSQL) |
->default($value) |
カラムの「既定の値」を決める |
->first() |
表の「いちばん前」に置く(MariaDB / MySQL) |
->from($integer) |
自動で増える値の、最初の値を決める(MariaDB / MySQL / PostgreSQL) |
->instant() |
「instant」操作でカラムを足す・変える(MySQL) |
->invisible() |
SELECT * から、カラムを見えなくする(MariaDB / MySQL) |
->lock($mode) |
カラムの操作のロックの種類を決める(MySQL) |
->nullable($value = true) |
カラムに NULL(値なし)を入れてよいことにする |
->storedAs($expression) |
保存される生成カラムを作る(MariaDB / MySQL / PostgreSQL / SQLite) |
->unsigned() |
INTEGER のカラムを UNSIGNED(マイナスなし)にする(MariaDB / MySQL) |
->using($expression) |
カラムの型を変えるときの、変換の式を決める(PostgreSQL) |
->useCurrent() |
TIMESTAMP の既定の値を CURRENT_TIMESTAMP(いまの日時)にする |
->useCurrentOnUpdate() |
行を更新したとき、TIMESTAMP を CURRENT_TIMESTAMP にする(MariaDB / MySQL) |
->virtualAs($expression) |
保存されない仮想の生成カラムを作る(MariaDB / MySQL / SQLite) |
->generatedAs($expression) |
シーケンスの設定を決めた、アイデンティティカラム(自動で番号を出すカラム)を作る(PostgreSQL) |
->always() |
アイデンティティカラムで、入力より、シーケンスの値を優先するかを決める(PostgreSQL) |
既定の値の式#
default には、値か、Illuminate\Database\Query\Expression を渡せます。Expression を使うと、Laravel は値を引用符で囲まないので、データベース独自の関数が使えます。JSON のカラムに既定の値を入れたいときに、とくに便利です。
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
};
注意
既定の値の式に対応しているかは、データベースのドライバ、データベースの版、カラムの型によります。データベースの説明書を見てください。
カラムの並び順#
MariaDB と MySQL では、after を使って、すでにあるカラムのあとに、カラムを足せます。
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
instant 操作#
MySQL では、カラムの定義に instant をつなげると、MySQL の「instant」アルゴリズム(やり方)で、カラムを足したり変えたりします。このやり方なら、表を作り直さずに、ある種の変更ができ、表が大きくても、ほぼ一瞬で終わります。
$table->string('name')->nullable()->instant();
instant でカラムを足せるのは、表のいちばん後ろだけなので、instant は after や first と一緒には使えません。また、すべての型や操作に対応しているわけではありません。合わない操作だと、MySQL がエラーを出します。
どの操作が instant に対応しているかは、MySQL の説明書で確かめます。
DDL のロック#
DDL は、表の形を作ったり変えたりする SQL のことです。MySQL では、カラム・インデックス・外部キーの定義に lock をつなげると、表の形を変えている間に、表へどんな鍵(ロック)をかけるかを決められます。ロックの種類は4つあります。
| 種類 | 働き |
|---|---|
none |
読むことも書くことも、同時にできる |
shared |
読むことは同時にできるが、書くことはできない |
exclusive |
同時のアクセスを、すべて止める |
default |
MySQL がいちばんよい種類を選ぶ |
$table->string('name')->lock('none');
$table->index('email')->lock('shared');
合わない種類を選ぶと、MySQL がエラーを出します。lock は instant と一緒に使うこともできます。
$table->string('name')->instant()->lock('none');
カラムを変える#
change は、すでにあるカラムの型や性質を変えます。たとえば string のカラムを大きくしたいときに使えます。name カラムを 25 から 50 に大きくする例です。カラムの新しい形を書いて、change を呼びます。
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});
カラムを変えるとき、残したい修飾子は、全部、書き直す必要があります。書かなかったものは、なくなります。たとえば、unsigned・default・comment を残すには、それぞれを呼びます。
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});
change は、カラムのインデックスは変えません。変えたいときは、インデックスの修飾子で、足したり消したりします。
// Add an index...
$table->bigIncrements('id')->primary()->change();
// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();
PostgreSQL でカラムを変える#
PostgreSQL でカラムの型を変えるときは、using で、いまの値を新しい型に変える式を決められます。
Schema::table('users', function (Blueprint $table) {
$table->date('birthday')->using('birthday::date')->change();
});
カラムの名前を変える#
カラムの名前を変えるには、スキーマビルダの renameColumn を使います。
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
カラムを消す#
カラムを消すには、スキーマビルダの dropColumn を使います。
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
カラム名の配列を渡すと、いくつものカラムを一度に消せます。
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
カラムを消す近道のメソッド#
よくあるカラムを消すための、便利なメソッドがあります。
| メソッド | 説明 |
|---|---|
$table->dropMorphs('morphable'); |
morphable_type と morphable_id のカラムを消す |
$table->dropRememberToken(); |
remember_token のカラムを消す |
$table->dropSoftDeletes(); |
deleted_at のカラムを消す |
$table->dropSoftDeletesTz(); |
dropSoftDeletes() の別名 |
$table->dropTimestamps(); |
created_at と updated_at のカラムを消す |
$table->dropTimestampsTz(); |
dropTimestamps() の別名 |
インデックス#
インデックスは、本の索引のように、データを速く探すための目印です。
インデックスを作る#
スキーマビルダは、いろいろな種類のインデックスに対応しています。次の例は、email カラムを作り、値が重ならない(unique)ようにします。カラムの定義に unique をつなげると、インデックスもできます。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
カラムを作ったあとで、インデックスを作ることもできます。スキーマビルダの unique を呼び、インデックスを付けるカラムの名前を渡します。
$table->unique('email');
カラム名の配列を渡すと、複合インデックス(複数のカラムをまとめたインデックス)になります。
$table->index(['account_id', 'created_at']);
インデックスを作るとき、Laravel は、表の名前・カラムの名前・インデックスの種類から、インデックスの名前を自動で付けます。2つ目の引数に、自分で名前を渡すこともできます。
$table->unique('email', 'unique_email');
インデックスの種類#
Blueprint には、対応している種類ごとにメソッドがあります。どれも、2つ目の引数に、インデックスの名前を渡せます。省くと、表とカラムの名前、種類から、名前が決まります。
| メソッド | 説明 |
|---|---|
$table->primary('id'); |
主キーを足す |
$table->primary(['id', 'parent_id']); |
複合の主キーを足す |
$table->unique('email'); |
値が重ならないインデックスを足す |
$table->index('state'); |
ふつうのインデックスを足す |
$table->fullText('body'); |
全文インデックスを足す(MariaDB / MySQL / PostgreSQL) |
$table->fullText('body')->language('english'); |
言語を決めた全文インデックスを足す(PostgreSQL) |
$table->spatialIndex('location'); |
空間インデックスを足す(SQLite 以外) |
$table->vectorIndex('embedding'); |
ベクトルインデックスを足す(MariaDB / PostgreSQL) |
止めずにインデックスを作る(オンライン)#
既定では、大きな表にインデックスを作っている間、表がロックされて、読むことも書くことも止まる場合があります。PostgreSQL と SQL Server では、インデックスの定義に online をつなげると、表をロックせずに作れます。作っている間も、アプリは読み書きを続けられます。
$table->unique('email')->online();
PostgreSQL では、インデックスを作る文に CONCURRENTLY が付きます。SQL Server では、WITH (online = on) が付きます。
MySQL では、インデックスや外部キーの定義に inplace をつなげると、その操作に INPLACE アルゴリズム(表をまるごと写し直さずに、その場で変えるやり方)を使わせられます。
$table->index('email')->inplace();
$table->foreign('user_id')->references('id')->on('users')->inplace();
inplace は、lock と組み合わせて、ロックのかけ方も決められます。
$table->index('email')->inplace()->lock('none');
外部キーの操作で inplace を使うときは、外部キーのチェックを、止めておく必要があります。
どの操作が INPLACE やロックの種類に対応しているかは、MySQL の説明書で確かめます。
インデックスの名前を変える#
インデックスの名前を変えるには、Blueprint の renameIndex を使います。1つ目に、いまの名前、2つ目に、新しい名前を渡します。
$table->renameIndex('from', 'to');
インデックスを消す#
インデックスを消すには、インデックスの名前を指定します。既定では、Laravel が、表の名前・カラムの名前・種類から、名前を付けています。例を並べます。
| メソッド | 説明 |
|---|---|
$table->dropPrimary('users_id_primary'); |
users 表の主キーを消す |
$table->dropUnique('users_email_unique'); |
users 表の、値が重ならないインデックスを消す |
$table->dropIndex('geo_state_index'); |
geo 表の、ふつうのインデックスを消す |
$table->dropFullText('posts_body_fulltext'); |
posts 表の全文インデックスを消す |
$table->dropSpatialIndex('geo_location_spatialindex'); |
geo 表の空間インデックスを消す(SQLite 以外) |
$table->dropVectorIndex('documents_embedding_vectorindex'); |
documents 表のベクトルインデックスを消す |
インデックスを消すメソッドにカラム名の配列を渡すと、表の名前・カラム・種類から、決まりどおりの名前が作られます。
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});
外部キー制約#
外部キー制約は、表どうしのつながりが壊れないように、データベースで守らせる決まりです。たとえば、posts 表に user_id のカラムを作り、users 表の id を指すようにします。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
この書き方は長いので、Laravel には、決まりを使った、短い書き方があります。カラムを foreignId で作ると、上の例を次のように書き直せます。
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});
foreignId は、UNSIGNED BIGINT 相当のカラムを作ります。constrained は、Laravel の名前の決まりから、指す先の表とカラムを決めます。表の名前が決まりと合わないときは、constrained に表の名前を渡します。作るインデックスの名前も渡せます。
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
});
制約の「on delete」(指す行が消えたとき)と「on update」(指す行が変わったとき)の動きも決められます。
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
これらの動きには、読みやすい別の書き方もあります。
| メソッド | 説明 |
|---|---|
$table->cascadeOnUpdate(); |
更新を、つながった行にも伝える |
$table->restrictOnUpdate(); |
更新を禁止する |
$table->nullOnUpdate(); |
更新されたら、外部キーの値を NULL にする |
$table->noActionOnUpdate(); |
更新のときは何もしない |
$table->cascadeOnDelete(); |
削除を、つながった行にも伝える |
$table->restrictOnDelete(); |
削除を禁止する |
$table->nullOnDelete(); |
削除されたら、外部キーの値を NULL にする |
$table->noActionOnDelete(); |
つながった子の行があれば、削除させない |
ほかのカラムの修飾子は、constrained より前に呼びます。
$table->foreignId('user_id')
->nullable()
->constrained();
外部キーを消す#
外部キーを消すには、dropForeign に、消す外部キー制約の名前を渡します。外部キー制約の名前は、インデックスと同じ決まりで付きます。つまり、表の名前とカラムの名前に、「_foreign」を付けたものです。
$table->dropForeign('posts_user_id_foreign');
外部キーのカラムの名前を入れた配列を渡すこともできます。Laravel の名前の決まりで、外部キー制約の名前に直されます。
$table->dropForeign(['user_id']);
外部キー制約を入り切りする#
マイグレーションの中で、外部キー制約を有効にしたり、無効にしたりできます。
| メソッド | 働き |
|---|---|
Schema::enableForeignKeyConstraints() |
外部キー制約を有効にする |
Schema::disableForeignKeyConstraints() |
外部キー制約を無効にする |
Schema::withoutForeignKeyConstraints() |
クロージャの中だけ、外部キー制約を無効にする |
Schema::enableForeignKeyConstraints();
Schema::disableForeignKeyConstraints();
Schema::withoutForeignKeyConstraints(function () {
// Constraints disabled within this closure...
});
注意
SQLite は、既定では外部キー制約が無効です。SQLite を使うときは、マイグレーションで外部キーを作る前に、データベースの設定で、外部キーの対応を有効にしてください。
イベント#
マイグレーションの操作ごとに、イベント(「起きた」という知らせ)が出ます。SchemaDumped と SchemaLoaded 以外は、どれも Illuminate\Contracts\Database\Events\MigrationEvent インターフェイス(クラスが持つべきメソッドを決めた約束)を満たしています。
| クラス | 説明 |
|---|---|
Illuminate\Database\Events\DatabaseRefreshed |
migrate:fresh か migrate:refresh が終わった |
Illuminate\Database\Events\MigrationsStarted |
マイグレーションのバッチを動かす直前 |
Illuminate\Database\Events\MigrationsEnded |
マイグレーションのバッチが終わった |
Illuminate\Database\Events\MigrationStarted |
マイグレーション1つを動かす直前 |
Illuminate\Database\Events\MigrationEnded |
マイグレーション1つが終わった |
Illuminate\Database\Events\NoPendingMigrations |
マイグレーションのコマンドが、動かす分がないと分かった |
Illuminate\Database\Events\SchemaDumped |
データベースのスキーマのダンプが終わった |
Illuminate\Database\Events\SchemaLoaded |
すでにあるスキーマのダンプを読み込んだ |
関連するページ#
公式ドキュメント(英語)
2026年10月5日時点の内容をもとに、日本語でまとめています。