1.

MySQL/MariaDBのカラム定義確認|権限・既定値・ORMとの違い

カラム情報は、実DBとモデル定義を分けて確認する

見える列を対象と権限で限定し、ORMモデルの項目と実DBのカラムを区別する図

メタデータ親ページから子ページを選択できます。本記事はその実子で、対話コマンドの使い分けはテーブル定義の確認へ進めます。MySQL/MariaDBの手順を中心に、既存の他製品・ORMの比較も条件付きで保持しています。

2026-10-26にMySQL8.4.13 / MariaDB11.8.9-ubu2404、既存のLaravel13.34.0 / Django5.2.18で新規検体を確認しました。新しい依存・本番DBの権限/設定・アプリの.envは変更していません。旧版の全コードや他DB/全driverまで実行した保証ではありません。

1. schema/表を絞り、列の順序と属性を読む

以下は定義確認記事で準備した使い捨て検体用です。名前を省略して全DBを走査せず、対象と権限を先に確認します。アプリから値を渡す場合は値をバインドし、識別子との違いにも注意します。

SELECT TABLE_SCHEMA,TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,
       DATA_TYPE,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,
       CHARACTER_SET_NAME,COLLATION_NAME,EXTRA,COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA='cwiki_w28' AND TABLE_NAME='users'
ORDER BY ORDINAL_POSITION;

検体ではid/email/display_name/no_default/blank_default/generated_lengthの6列がORDINAL_POSITION順に見えました。COLUMN_TYPEのunsigned、NULL、既定値、charset/collation、生成列のEXTRA、COMMENTをそれぞれ確認します。生成式や索引/制約の全定義までこの1照会だけで分かったとは扱いません。

列権限をid/emailだけにした接続では同じ照会が2列になりました。空欄/NULL/0件は「ない」の断定ではなく、項目の意味・製品の表示形式・権限・対象を調べます。内部のカラム名やコメント、定義全文を公開ログへそのまま出しません。

2. Laravelの現行ネイティブAPIを確認する

Laravel13にはgetColumns/getColumnType等のネイティブなSchema APIがあります。DBALを一律に必須とせず、旧getDoctrineSchemaManagerを現行版の操作としてそのまま呼びません。既存アプリでは接続alias/権限に合わせます。次は既存vendorだけを使うstandaloneの検体用コードで、本番bootstrapや資格情報を読み込みません。

新規検体のusersだけSELECTできるmetadata_readerと、一時port/passwordを実行環境に用意した場合の例です。環境変数CWIKI_METADATA_PORT / CWIKI_METADATA_PASSWORDは検体のものだけを使い、本番の.envや既存poolを変更しません。

PHPのrequireは検体用ファイル配置と既存vendorの位置を前提にしています。任意のアプリへそのまま置く完成設定ではなく、検体のautoload配置/driver/依存版も照合します。

<?php
// Standalone disposable fixture; do not load production bootstrap or credentials.
require dirname(__DIR__,4).'/vendor/autoload.php';
use Illuminate\Database\Capsule\Manager as Capsule;

$port=filter_var(getenv('CWIKI_METADATA_PORT'),FILTER_VALIDATE_INT);
$password=getenv('CWIKI_METADATA_PASSWORD');
if(PHP_SAPI!=='cli'||!$port||$port<1||$port>65535||!is_string($password)||$password==='')throw new RuntimeException('Fixture environment required');
$capsule=new Capsule;
$capsule->addConnection(['driver'=>'mysql','host'=>'127.0.0.1','port'=>$port,'database'=>'cwiki_w28','username'=>'metadata_reader','password'=>$password,'charset'=>'utf8mb4']);
$schema=$capsule->getConnection()->getSchemaBuilder();
$columns=$schema->getColumns('users');
echo json_encode(['laravel'=>Illuminate\Foundation\Application::VERSION,'database_columns'=>array_column($columns,'name'),'email_type'=>$schema->getColumnType('users','email'),'missing_column'=>$schema->hasColumn('users','missing_fixture_column')],JSON_THROW_ON_ERROR);

検体ではDB側の6列、email_typeのvarchar、存在しない列のfalseを取得しました。列名の配列や型1つだけで、全DEFAULT/生成式/複合キー/復旧用DDLを得たとは扱いません。今回は既存アプリの認証/FPMからの実操作や、旧DBAL APIの全版互換は未検証です。

3. Djangoのモデルと実DBの差を見落とさない

Model._meta.get_fields()はモデル定義の情報で、実DBへ問い合わせて一致を保証する機能ではありません。次はid/emailだけを宣言したmanaged=Falseの検体モデルと、読取専用接続による実DB introspectionを比較します。project設定を読み込まず、migrateやモデル作成は実行しません。

"""Standalone fixture, no project settings, migrations or production connection."""
import json
import os
from django.conf import settings

port=int(os.environ['CWIKI_METADATA_PORT'])
if not 1<=port<=65535 or not os.environ['CWIKI_METADATA_PASSWORD']:
    raise RuntimeError('Fixture environment required')
settings.configure(INSTALLED_APPS=[],DATABASES={'default':{
    'ENGINE':'django.db.backends.mysql','HOST':'127.0.0.1','PORT':port,
    'NAME':'cwiki_w28','USER':'metadata_reader','PASSWORD':os.environ['CWIKI_METADATA_PASSWORD'],
}})
import django
django.setup()
from django.db import connection,models

class DeclaredUser(models.Model):
    id=models.IntegerField(primary_key=True)
    email=models.CharField(max_length=40)
    class Meta:
        app_label='isolated_metadata'
        db_table='users'
        managed=False

try:
    model_fields=[f.name for f in DeclaredUser._meta.get_fields()]
    with connection.cursor() as cursor:
        database_columns=[c.name for c in connection.introspection.get_table_description(cursor,'users')]
    print(json.dumps({'model_fields':model_fields,'database_columns':database_columns}))
finally:
    connection.close()

モデルの項目は2つ、DBの列は6つになりました。差があることを理由にDBへ列を追加/削除せず、接続alias・既存schema・未反映変更・モデルの対象を調べます。inspectdbは別の逆生成処理で、Django5.2の対象指定は位置引数と--databaseです。旧コメントの--table-name-filterは今回のCLI parserに存在せず、そのまま実行しません。生成したモデルも完全な正本/移行計画とは扱わず確認します。

4. 他DBのコマンドや旧出力を転用しない

psql/SQL*Plus/sqlite3のプロンプトや\d/\G/SET LONG等は、それぞれのクライアント操作とSQLを区別します。SQLiteのtable_infoは生成/hidden列を全て含む照会ではなく、必要な場合は対象版のtable_xinfo等を確認します。Oracle/SQL Serverの権限やschema/列順も別です。後の元のinformation_schema.COLUMNS出力は当時の例として保持し、現行版の列数/型長が完全一致するとは主張しません。

この記事の要点
  • MySQL: DESCRIBE tablename または SHOW COLUMNS / SHOW CREATE TABLE / information_schema.COLUMNS
  • PostgreSQL: \d+ tablename (psql)、または information_schema.columns / pg_attribute
  • Oracle: USER_TAB_COLUMNS / ALL_TAB_COLUMNS / DESC tablename (SQL*Plus)
  • SQL Server: sp_columns または INFORMATION_SCHEMA.COLUMNS / sys.columns
  • ORM 経由: Laravel は Schema::getColumnListing / Schema::hasColumn、Django は Model._meta.get_fields()

カラム定義確認の概要

テーブルにどんなカラムが定義されているか(カラム名・データ型・NULL 可否・デフォルト値・コメント等)を確認する方法は、DB ごとに方言が分かれます。本記事では主要 4 種 DB と代表 ORM での確認方法をまとめます。

MySQL / MariaDB

DESCRIBE / SHOW COLUMNS

旧例の注意:MySQL/MariaDBの別例です。サンプル出力の列/Key/Defaultだけで全定義を判断せず、権限・対象・生成列等を確認します。

-- 最短: DESCRIBE
DESCRIBE users;
DESC users;                          -- 短縮形

-- SHOW COLUMNS (同等)
SHOW COLUMNS FROM users;
SHOW FULL COLUMNS FROM users;        -- コメント列も表示

-- 結果イメージ
-- +-------+--------------+------+-----+---------+----------------+
-- | Field | Type         | Null | Key | Default | Extra          |
-- +-------+--------------+------+-----+---------+----------------+
-- | id    | bigint       | NO   | PRI | NULL    | auto_increment |
-- | name  | varchar(255) | NO   |     | NULL    |                |
-- | email | varchar(255) | YES  | UNI | NULL    |                |
-- +-------+--------------+------+-----+---------+----------------+

SHOW CREATE TABLE

CREATE TABLE 文を逆生成。ENGINE / CHARSET / インデックス / 外部キー等の表定義を確認します。行/trigger/全依存の復旧や全項目の可視性を保証するものではありません。

旧例の注意:CREATEの表示例で、行/trigger/権限/全依存のbackupではありません。\Gをdriver SQLとして送らず、出力を実表へ再実行しません。

SHOW CREATE TABLE users\G

-- CREATE TABLE `users` (
--   `id` bigint unsigned NOT NULL AUTO_INCREMENT,
--   `name` varchar(255) NOT NULL,
--   `email` varchar(255) DEFAULT NULL,
--   `created_at` timestamp NULL DEFAULT NULL,
--   PRIMARY KEY (`id`),
--   UNIQUE KEY `users_email_unique` (`email`)
-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

information_schema.COLUMNS

旧例の注意:COLUMN_TYPEだけではcollationや生成式の全情報は取得できません。schema/表/列順と必要な属性を別に照合します。

SELECT column_name, data_type, character_maximum_length,
       is_nullable, column_default, column_comment
FROM   information_schema.columns
WHERE  table_schema = 'myapp'
  AND  table_name   = 'users'
ORDER  BY ordinal_position;

-- データ型が enum / set / collation を含む全件取得
SELECT column_name, column_type
FROM   information_schema.columns
WHERE  table_schema = DATABASE() AND table_name = 'users';

PostgreSQL

psql の \d コマンド

旧例の注意:PGのpsqlプロンプト/メタコマンドです。そのままdriver SQLへ送らず、schema/識別子と実接続を確認します。

-- 簡易表示
mydb=# \d users

-- 拡張表示(コメント・統計を含む)
mydb=# \d+ users

-- 全テーブル一覧
mydb=# \dt
mydb=# \dt public.*

-- スキーマ別
mydb=# \dn         -- スキーマ一覧
mydb=# \dt app.*

-- 索引一覧
mydb=# \di

-- 関数定義
mydb=# \df
mydb=# \sf func_name

information_schema.columns

旧例の注意:PG用のCOLUMNS照会です。標準名でも全製品の型/属性/可視範囲が同じではありません。

SELECT column_name, data_type, character_maximum_length,
       is_nullable, column_default
FROM   information_schema.columns
WHERE  table_schema = 'public'
  AND  table_name   = 'users'
ORDER  BY ordinal_position;

pg_catalog 系

旧例の注意:PGカタログ例です。regclassの対象/権限/名前の引用と生成列等の対象版を調べ、全定義の完全再現としません。

SELECT a.attname AS column_name,
       pg_catalog.format_type(a.atttypid, a.atttypmod) AS data_type,
       a.attnotnull AS not_null,
       pg_get_expr(d.adbin, d.adrelid) AS default
FROM   pg_attribute a
LEFT   JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
WHERE  a.attrelid = 'public.users'::regclass
  AND  a.attnum > 0 AND NOT a.attisdropped
ORDER  BY a.attnum;

Oracle

SQL*Plus DESC

旧例の注意:SQL*Plusの表示例です。プロンプトや出力をSQLとして流しません。

SQL> DESC users
 Name              Null?    Type
 ----------------- -------- ----------------
 ID                NOT NULL NUMBER
 NAME              NOT NULL VARCHAR2(255)
 EMAIL                      VARCHAR2(255)
 CREATED_AT                 TIMESTAMP(6)

ディクショナリビュー

旧例の注意:OracleのUSER/ALL/DBAを区別します。既存主キー照会はUSER系なので同じ所有範囲内の結合であり、他schemaを混ぜる取得とは分けます。複合列順は別途確認します。

-- 自スキーマのテーブル
SELECT column_name, data_type, data_length, nullable, data_default
FROM   user_tab_columns
WHERE  table_name = 'USERS'
ORDER  BY column_id;

-- 全スキーマ (権限あるもの)
SELECT owner, table_name, column_name, data_type, nullable
FROM   all_tab_columns
WHERE  owner = 'APP' AND table_name = 'USERS';

-- DBA 権限あり
SELECT * FROM dba_tab_columns WHERE owner = 'APP';

-- 主キー / 索引付き列
SELECT cols.table_name, cols.column_name, cons.constraint_type
FROM   user_cons_columns cols
JOIN   user_constraints cons ON cols.constraint_name = cons.constraint_name
WHERE  cons.constraint_type = 'P';     -- 主キー

DDL を逆生成

旧例の注意:SQL*PlusのSET LONGはクライアント表示設定です。DBMS_METADATAの所有者/権限/出力範囲を確認し、完全復旧とは扱いません。

SET LONG 100000
SELECT DBMS_METADATA.GET_DDL('TABLE', 'USERS', 'APP') FROM dual;

SQL Server

旧例の注意:SQL Server用です。schema/対象とキー順を絞り、名前だけの一致や表示長を全製品へ転用しません。

-- sp_columns 手続き
EXEC sp_columns 'users';
EXEC sp_help 'users';                 -- より詳細

-- INFORMATION_SCHEMA
SELECT column_name, data_type, character_maximum_length,
       is_nullable, column_default
FROM   information_schema.columns
WHERE  table_schema = 'dbo' AND table_name = 'users'
ORDER  BY ordinal_position;

-- sys.columns
SELECT c.name, t.name AS type, c.max_length, c.is_nullable
FROM   sys.columns c
JOIN   sys.types t ON c.user_type_id = t.user_type_id
WHERE  object_id = OBJECT_ID('dbo.users');

-- 主キー
SELECT i.name, c.name
FROM   sys.indexes i
JOIN   sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN   sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE  i.is_primary_key = 1 AND i.object_id = OBJECT_ID('dbo.users');

SQLite

旧例の注意:SQLiteのシェル操作とSQLを分けます。table_infoは生成/hidden列を全て返すものではなく、対象版のtable_xinfo等を調べます。

-- sqlite3 シェル
sqlite> .schema users
sqlite> .tables
sqlite> PRAGMA table_info(users);

-- SQL 経由
SELECT name, type, "notnull", dflt_value, pk
FROM   pragma_table_info('users');

Laravel での確認

旧例の注意:旧Laravelの例です。現行13ではDBAL必須ではなく、旧getDoctrineSchemaManagerは利用できません。型名の表示やAPIの対象版も違うため、新しい検体のnative APIを参照します。

use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;

// カラム名の配列
$cols = Schema::getColumnListing('users');
// → ['id', 'name', 'email', 'password', ...]

// カラム存在チェック
if (Schema::hasColumn('users', 'email_verified_at')) { /* ... */ }

// 個別カラムの型 (Doctrine DBAL 必須)
$type = Schema::getColumnType('users', 'name');     // 'string'

// Doctrine DBAL 経由でメタ情報
$columns = DB::connection()
    ->getDoctrineSchemaManager()
    ->listTableColumns('users');
foreach ($columns as $name => $col) {
    echo $name . ' : ' . $col->getType()->getName() . PHP_EOL;
}

// 生 SQL で確認
print_r(DB::select('DESCRIBE users'));
print_r(DB::select('SHOW CREATE TABLE users'));

Django / Python の場合

旧例の注意:モデル._metaは実DBの照会ではありません。旧inspectdbのtable-name-filterは今回5.2 parserにないオプションで、SQLAlchemyも対象接続/schema/版に合わせます。依存の追加やmigrateを診断の準備にしません。

# Django ORM のメタ情報
from myapp.models import User
for f in User._meta.get_fields():
    print(f.name, type(f).__name__, getattr(f, 'max_length', None))

# Django 管理コマンド
# python manage.py inspectdb users   --table-name-filter=users

# SQLAlchemy
from sqlalchemy import inspect
inspector = inspect(engine)
for col in inspector.get_columns('users'):
    print(col['name'], col['type'], col['nullable'])

用途別の早見表

やりたいことMySQLPostgreSQLOracleSQL Server
クイック確認DESC users\d usersDESC userssp_columns 'users'
DDL 逆生成SHOW CREATE TABLEpg_dump -s -t(-tは対象、-sは定義のみ。依存範囲も確認)DBMS_METADATA.GET_DDLSSMS のスクリプト生成
メタデータ参照(製品別)information_schema.columnsinformation_schema.columnsUSER_TAB_COLUMNSINFORMATION_SCHEMA.COLUMNS
システムカタログinformation_schema中心。用途別のperformance_schema等と区別pg_attributeDBA_TAB_COLUMNSsys.columns

FAQ

Q: information_schema と システムカタログ、どちらを使うべき?
A: 移植性を重視するなら information_schema(SQL 標準)、DB 固有機能 (PG の partial index 等) を見るならシステムカタログ。

Q: 大量のテーブルから特定の名前のカラムを横断検索したい
A: schema/対象/可視範囲を限定して検索し、schema名・表名・列名と列順も返します。権限で見えない対象を含む全DB/全表を取得できたとは扱いません。

Q: 本番でいきなり SHOW FULL COLUMNS を打って良い?
A: 読取でも負荷/metadata lock/対象数/権限/キャッシュと製品版を確認します。無影響/常に軽量とは断定せず、対象schema/表を限定します。確認のために設定/権限を追加しません。

元のCOLUMNS出力と検索例

元v2の2表を当時の記録として保持します。固定の出力見本を現行DBの仕様表へ読み替えません。

INFORMATION_SCHEMA.COLUMNSテーブルにカラム定義が格納されている。

旧例の注意:当時のinformation_schema.COLUMNSの出力例です。現行版の列数/型長/既定値との完全一致や、mysqlプロンプト込みのSQL実行を保証しません。

mysql> DESC INFORMATION_SCHEMA.COLUMNS;
+--------------------------+---------------------+------+-----+---------+-------+
| Field                    | Type                | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG            | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA             | varchar(64)         | NO   |     |         |       |
| TABLE_NAME               | varchar(64)         | NO   |     |         |       |
| COLUMN_NAME              | varchar(64)         | NO   |     |         |       |
| ORDINAL_POSITION         | bigint(21) unsigned | NO   |     | 0       |       |
| COLUMN_DEFAULT           | longtext            | YES  |     | NULL    |       |
| IS_NULLABLE              | varchar(3)          | NO   |     |         |       |
| DATA_TYPE                | varchar(64)         | NO   |     |         |       |
| CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_OCTET_LENGTH   | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_PRECISION        | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_SCALE            | bigint(21) unsigned | YES  |     | NULL    |       |
| DATETIME_PRECISION       | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_SET_NAME       | varchar(32)         | YES  |     | NULL    |       |
| COLLATION_NAME           | varchar(32)         | YES  |     | NULL    |       |
| COLUMN_TYPE              | longtext            | NO   |     | NULL    |       |
| COLUMN_KEY               | varchar(3)          | NO   |     |         |       |
| EXTRA                    | varchar(30)         | NO   |     |         |       |
| PRIVILEGES               | varchar(80)         | NO   |     |         |       |
| COLUMN_COMMENT           | varchar(1024)       | NO   |     |         |       |
+--------------------------+---------------------+------+-----+---------+-------+

 

例えば、TESTと名の付くカラムを持つテーブルを検索したい場合は、以下のコマンドを実行する。

旧例の注意:schema条件のない旧検索例です。可視範囲全体を走査し得るため、新規検体でも対象schema/表を限定して確認します。

SELECT TABLE_NAME, COLUMN_NAME 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE COLUMN_NAME LIKE '%TEST%';

 

確認範囲と一次資料

新規の小規模InnoDB検体と限定した読取権限で確認した範囲です。全負荷/全権限/全製品・全GUI/旧dumpの実行・本番復旧/既存アプリの全設定を保証せず、調査のために本番設定/依存/権限を追加していません。

子ページ

子ページはありません

同階層のページ

同階層のページはありません