Help us understand the problem. What is going on with this article?

A5:SQL Mk-2 に頼らない MySQL のテーブル定義出力

こちらは ZYYX Advent Calendar 2019 2日目の記事です。

テーブル定義書の生成といえば、おなじみの A5:SQL Mk-2 でエクセルベースのテーブル定義書をエクスポートするのが定番ですが、残念ながら Windows のみで Mac に対応していません。
Wine で強引に exe を実行するという方法もありますが、今回はよりカジュアルに Mac でHTML・Markdownでテーブル定義書を書き出す方法をご紹介します。

  • mysqldump で DDL をXML形式で出力
  • XSLT をあててHTMLやMarkdown に変換

以上の流れになります。

DDLのエクスポート

まずは mysqldump コマンドでXML形式のDDLをエクスポートします。

mysqldump -u <ユーザー名> -p --no-data --xml <データベース名> > <出力ファイル名(XML)>

XSLT のアタッチ

dump した XML に xsltproc で変換したいフォーマット用のXSLTをあてて変換します。

# HTMLに変換
xsltproc -o <出力ファイル名(HTML)> htmlstyle.xslt <XMLファイルパス>

# Markdownに変換
xsltproc -o <出力ファイル名(md)> mdstyle.xslt <XMLファイルパス>

htmlstyle.xsl(HTMLに変換)

<?xml version="1.0" encoding="utf8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://sqlfairy.sourceforge.net/sqlfairy.xml">
    <xsl:output method="html" encoding="utf8" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"/>

    <xsl:template match="database">
        <html lang="ja">
            <head>
                <meta charset="utf-8"/>
                <title><xsl:value-of select="@name"/> テーブル定義</title>
                <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
                <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
                <style>
                    table.htable {
                        margin: 3em auto 1em auto !important;
                    }
                    table.htable th {
                        border-left: 10px solid #e5e5e5 !important;
                    }
                    footer {
                        border-top: 1px solid #e5e5e5;
                        padding: 0.5em;
                    }
                </style>
            </head>

            <body>
                <div class="container">
                    <h1 class="page-header"><xsl:value-of select="@name"/> テーブル定義</h1>
                    <xsl:apply-templates select="table_structure"/>
                </div>
                <footer class="text-center">
                    your company
                </footer>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="table_structure">
        <h2 class="table-header"><xsl:value-of select="@name"/></h2>
        <table class="table table-bordered htable">
            <tbody>
                <tr class="active">
                    <th>論理テーブル名</th>
                    <td>
                        <xsl:value-of select="options/@Comment"/>
                    </td>
                </tr>
                <tr class="active">
                    <th>物理テーブル名</th>
                    <td><xsl:value-of select="@name"/></td>
                </tr>
            </tbody>
        </table>
        <table class="table table-condensed">
            <thead>
                <tr>
                    <th class="text-right">#</th>
                    <th>論理名</th>
                    <th>物理名</th>
                    <th>データ型</th>
                    <th>NULL</th>
                    <th>デフォルト値</th>
                    <th>主キー</th>
                    <th>ユニーク</th>
                </tr>
            </thead>
            <tbody>
                <xsl:apply-templates select="field"/>
            </tbody>
        </table>
        <table class="table table-condensed">
            <thead>
                <tr>
                    <th>インデックス名</th>
                    <th>カラム</th>
                    <th>複合キー順序</th>
                    <th>NULL</th>
                    <th>UNIQ</th>
                </tr>
            </thead>
            <tbody>
                <xsl:apply-templates select="key"/>
            </tbody>
        </table>
    </xsl:template>

    <xsl:template match="field">
        <tr>
            <td class="text-right"><xsl:value-of select="position()"/></td>
            <td><xsl:value-of select="@Comment"/></td>
            <td><xsl:value-of select="@Field"/></td>
            <td><xsl:value-of select="@Type"/></td>
            <td><xsl:if test="@Null='YES'"><span class="glyphicon glyphicon-ok"></span></xsl:if></td>
            <td><xsl:value-of select="@Default"/></td>
            <td><xsl:if test="@Key='PRI'"><span class="glyphicon glyphicon-ok"></span></xsl:if></td>
            <td><xsl:if test="@Key='UNI'"><span class="glyphicon glyphicon-ok"></span></xsl:if></td>
        </tr>
    </xsl:template>

    <xsl:template match="key">
        <tr>
            <td><xsl:value-of select="@Key_name"/></td>
            <td><xsl:value-of select="@Column_name"/></td>
            <td><xsl:value-of select="@Seq_in_index"/></td>
            <td><xsl:choose><xsl:when test="@Null != ''"><xsl:value-of select="@Null"/></xsl:when><xsl:otherwise>NO</xsl:otherwise></xsl:choose></td>
            <td><xsl:choose><xsl:when test="@Non_unique = '0'">YES</xsl:when><xsl:otherwise>NO</xsl:otherwise></xsl:choose></td>
        </tr>
    </xsl:template>
</xsl:stylesheet>

mdstyle.xsl(Markdownに変換)

<?xml version="1.0" encoding="utf8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://sqlfairy.sourceforge.net/sqlfairy.xml">
<xsl:output method="text" encoding="utf8"/>

<xsl:template match="database">
# <xsl:value-of select="@name"/> テーブル定義
<xsl:apply-templates select="table_structure"/>
</xsl:template>

<xsl:template match="table_structure">

## <xsl:value-of select="@name"/>
物理テーブル名|論理テーブル名
--------|--------
<xsl:value-of select="@name"/>|<xsl:value-of select="options/@Comment"/>

#### カラム情報
#|論理名|物理名|データ型|NULL|デフォルト値|主キー|Extra
----|----|----|----|----|----|----|---|
<xsl:apply-templates select="field"/>

#### インデックス情報
インデックス名|カラム|複合キー順序|NULL|UNIQ
----|----|----|----|----
<xsl:apply-templates select="key"/>
</xsl:template>

<xsl:template match="field">
<xsl:value-of select="position()"/>| <xsl:value-of select="@Comment"/> |<xsl:value-of select="@Field"/>|<xsl:value-of select="@Type"/>|<xsl:value-of select="@Null"/>|<xsl:choose><xsl:when test="@Default != ''"><xsl:value-of select="@Default"/></xsl:when><xsl:otherwise>n/a</xsl:otherwise></xsl:choose>|<xsl:choose><xsl:when test="@Key != ''"><xsl:value-of select="@Key"/></xsl:when><xsl:otherwise>n/a</xsl:otherwise></xsl:choose>|<xsl:choose><xsl:when test="@Extra != ''"><xsl:value-of select="@Extra"/></xsl:when><xsl:otherwise>n/a</xsl:otherwise></xsl:choose>|<xsl:text>
</xsl:text>
</xsl:template>

<xsl:template match="key">
<xsl:value-of select="@Key_name"/>| <xsl:value-of select="@Column_name"/>|<xsl:value-of select="@Seq_in_index"/>|<xsl:choose><xsl:when test="@Null != ''"><xsl:value-of select="@Null"/></xsl:when><xsl:otherwise>NO</xsl:otherwise></xsl:choose>|<xsl:choose><xsl:when test="@Non_unique = '0'">YES</xsl:when><xsl:otherwise>NO</xsl:otherwise></xsl:choose>|<xsl:text>
</xsl:text>
</xsl:template>

</xsl:stylesheet>

変換文書のイメージ

HTML
image.png

Markdown
image.png

HTML では bootstrap を読み込んでいるので、Webフォントなどのアイコンも利用できます。
MySQL テーブル仕様書メーカー的な何か の XSLT をベースにさせていただきました。

まとめ

XML と XSLT を使用して様々なフォーマットに変換することができました。
標準では対応していない形式でもちょっとした応用をするだけで変換できそうですね。

外部キー制約とかトリガーが XML にダンプされていませんが、これは --xml モードの場合、mysqlsump 内部で show keys from <テーブル名> コマンドを使った出力をしているためです。
バグとして公式のバグトラッカーに起票されていますが、結構昔なので対応されることはなさそうですね(笑)https://bugs.mysql.com/bug.php?id=66821

テーブル定義書としては「片手落ち」なので、あくまでカジュアルに定義を確認したい時などに使用範囲はとどめておきましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした