テーブル定義のexcelファイル出力(1)

テーブル定義って考えることが多くて大変だし、excel上だけで、作業するのも退屈なので、以前から実際のスキーマ情報からテーブル定義を自動生成したいとは思っていました。DBDesignerというソフトウェアで、実際のDBからテーブル定義をリバースエンジニアリングしてから、カラム名の日本語説明やら備考やらを書き込んで、HTMLリポートで出力ということも試してみたんですが、満足できませんでした。


最近Postgresqlを使うことが多いんですが、postgresqlでは、DBのオブジェクトにCOMMENTを付加することができるので、それを利用して日本語名やら備考を設定していけば、実際のDBからテーブル定義書を出力できるようにできます。

仕様

汚い仕様ですが、例えばカラムに対してのコメントは、「カラム名;備考」というように、;で区切った前がカラム名で;以降が備考というように設定することにしました。pgadmin3というツールを使えばコメントを付加するのは簡単です。できたらMySQLとかも対応できたらいいけど、必要にならないとやらないかも。(MySQLにコメントを付加する機能があるかどうかも知りません。)

実装

リハビリの意味も含めてperlで書きました。

DbDefInfo.pmDBD:PgPP で各テーブル、カラム情報をコメント付きでとってきます。
WriteExcelDbDefInfo.pmSpreadsheet::WriteExcelで、excelファイルを出力します。
create_table_def.pl実行のエントリポイント

途中で疲れてきたので、SQLとか変数名とかバグとかPODがないとか不快なものがあると思います。見付けたら直していきます。恥を忍んで貼り付けます。

DbDefInfo.pm

2007/09/18 SQL文が間違っているので後で修正しました。

package DbDefInfo;use strict;use warnings;our($VERSION, @ISA, @EXPORT, @EXPORT_OK);require Exporter;use Carp;$VERSION = '0.0001';@ISA = qw(Exporter);@EXPORT = qw(get_table_def_infos);@EXPORT_OK = qw();
 use DBI;my $column_info_query = <<EOD;
  SELECT DISTINCT
    PG_ATTRIBUTE.ATTNAME AS NAME,
    PG_TYPE.TYPNAME AS TYPE,
    PG_ATTRIBUTE.ATTTYPMOD - 4 AS SUBTYPE,
    PG_ATTRIBUTE.ATTNOTNULL AS NOTNULL,
    PG_ATTRDEF.ADSRC AS DEFAULT,
    PG_DESCRIPTION.DESCRIPTION AS DESCRIPTION,
    PG_ATTRIBUTE.ATTNUM AS NO,
    PG_ATTRIBUTE.ATTALIGN
  FROM
    PG_ATTRIBUTE
  INNER JOIN PG_CLASS ON 
    PG_CLASS.OID = PG_ATTRIBUTE.ATTRELID
  INNER JOIN PG_TYPE ON
    PG_ATTRIBUTE.ATTTYPID = PG_TYPE.OID
  LEFT JOIN PG_DESCRIPTION ON
    PG_CLASS.OID = PG_DESCRIPTION.OBJOID AND
    PG_ATTRIBUTE.ATTNUM = PG_DESCRIPTION.OBJSUBID
  LEFT JOIN PG_ATTRDEF ON 
      PG_ATTRIBUTE.ATTRELID = PG_ATTRDEF.ADRELID AND
      PG_ATTRIBUTE.ATTNUM = PG_ATTRDEF.ADNUM
  WHERE
    PG_CLASS.RELNAME='%s' AND
    PG_ATTRIBUTE.ATTNUM > 0
  ORDER BY
    PG_ATTRIBUTE.ATTNUM 
EOD
 my $keys_info_query = <<EOD;
  SELECT
   C.RELNAME AS TABLENAME, 
   A.ATTNAME AS COLUMNNAME,
   FCLASS.RELNAME AS FTABLENAME,
   FATTR.ATTNAME AS FCOLUMNNAME
  FROM
    PG_CONSTRAINT N
  INNER JOIN  PG_CLASS C
   ON N.CONRELID = C.OID
  INNER JOIN PG_ATTRIBUTE A
   ON A.ATTRELID = C.OID
  LEFT JOIN 
   PG_CLASS AS FCLASS ON
    N.CONFRELID = FCLASS.OID
  LEFT JOIN PG_ATTRIBUTE FATTR
   ON FATTR.ATTRELID = C.OID AND
      FATTR.ATTNUM = ANY(N.CONFKEY)
  WHERE
    A.ATTNUM =ANY (N.CONKEY) AND
    C.RELNAME = '%s'
EOD
 my $all_table_query = <<EOD;
  SELECT DISTINCT
    PG_CLASS.RELNAME,
    PG_DESCRIPTION.DESCRIPTION
  FROM
    PG_CLASS
  INNER JOIN 
    PG_TABLES ON
      PG_CLASS.RELNAME = PG_TABLES.TABLENAME
  LEFT JOIN
    PG_DESCRIPTION ON
      PG_CLASS.OID = PG_DESCRIPTION.OBJOID AND
      PG_DESCRIPTION.OBJSUBID = 0
  WHERE
    SCHEMANAME = '%s' AND PG_CLASS.RELKIND = 'r'
EOD
 sub get_all_tables {my ($db, $schema_name) = @_;my $st = $db->prepare(sprintf $all_table_query, $schema_name);my $res = $st->execute;my @table_infos;while (my ($table_name, $table_comment) = $st->fetchrow) {push @table_infos, {table_name => $table_name, table_comment => $table_comment};}$st->finish;return @table_infos;}
 sub get_keys_infos {my ($db, $table_name) = @_;my @keys;my $st_keys = $db->prepare(sprintf($keys_info_query, $table_name));my $res_columns = $st_keys->execute;while (my $row_hashref = $st_keys->fetchrow_hashref) {push @keys, $row_hashref;}$st_keys->finish;return @keys;}
 sub get_column_infos {my ($db, $table_name) = @_;my @columns;my $st_columns = $db->prepare(sprintf($column_info_query, $table_name));my $res_columns = $st_columns->execute;while (my $row_hashref = $st_columns->fetchrow_hashref) {push @columns, $row_hashref;}$st_columns->finish;return @columns;}
 sub get_table_def_infos {my $settings = shift;my $db = DBI->connect("DBI:$settings->{type}:host=$settings->{host};dbname=$settings->{dbname}",$settings->{user},$settings->{passwd})or die "DBI connect failed : $DBI::errstr";my @rows;for my $table_info (get_all_tables($db, $settings->{schema_name})) {my @columns = get_column_infos($db, $table_info->{table_name});my @keys = get_keys_infos($db, $table_info->{table_name});push @rows, { table_info => $table_info, column_infos => \@columns, key_infos => \@keys};}$db->disconnect;return @rows;}1;

続く

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください