将 MySQL 架构转换为 Github Wiki?

Convert MySQL schema to Github Wiki?

我正在使用 GitHub Wiki 页面记录一个项目,现在我想将 MySQL 数据库模式导出为 markdown 格式。有没有办法将 CLI 输出转换为 GitHub Wiki md?理想情况下作为表格。

我的输出如下所示:

您只需要删除 table 输出的第一行和最后一行并将 + 替换为 | 以获得 table.[=13 的降价格式=]

像这样:

|Field|Type|Null|Key|Default|Extra|
|-----|----|----|---|-------|-----|
|blockheight|int(11)|No|PRI|NULL||
...

这段代码比较长。我道歉。它由两个存储过程组成。您可能 运行 只满意第一个。第二个使用第一个的输出(第一个在 tables 中留下的数据)。您可能还希望将代码合二为一。但我把它们分开了。第二个存储过程产生类似于 describe myTable 的输出。但是它会在您想要这样的输出的数据库中执行 ALL tables。

您可以通过传递一个参数(字符串)供数据库报告来使用它。

我创建了一个单独的数据库,并且代码通过名称显式引用了该数据库中的 table。因此,如果您对该存储过程具有 EXECUTE 权限,则可以从任何当前数据库中 运行 它。因此,作为一个简单的测试,不要将报告数据库设置为您当前的数据库,而只需按名称调用存储过程(符合报告数据库名称)。这都显示在下面的测试块中。

两个存储过程

CREATE SCHEMA Reporting101a;    -- See **Note1**

DROP PROCEDURE IF EXISTS `Reporting101a`.`describeTables_v2a`;
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `Reporting101a`.`describeTables_v2a`(
    IN dbName varchar(100), -- the dbname to report table structures
    OUT theSession int, -- OUT parameter for session# assigned
    IN deleteSessionRows BOOL, -- true for delete rows when done from main reporting table for this session#
    IN callTheSecondStoredProc BOOL -- TRUE = output is from Pretty output in Second Stored Proc. FALSE= not so pretty output
)
BEGIN
    DECLARE thisTable CHAR(100);

    DROP TEMPORARY TABLE IF EXISTS Reporting101a.tOutput;
    CREATE TEMPORARY TABLE Reporting101a.tOutput
    (   id int auto_increment primary key,
        tblName varchar(100) not null,
        ordVal int not null,
        cField varchar(100) not null,
        cType varchar(100) not null,
        cNull varchar(100) not null,
        cKey varchar(100) not null,
        cDefault varchar(100) null,
        cExtra varchar(100) null
    );
    DROP TEMPORARY TABLE IF EXISTS Reporting101a.tOutput2;
    CREATE TEMPORARY TABLE Reporting101a.tOutput2
    (   tblName varchar(100) primary key,
        colCount int not null,
        cFieldMaxLen int not null,
        cTypeMaxLen int not null,
        cNullMaxLen int not null,
        cKeyMaxLen int not null,
        cDefaultMaxLen int not null,
        cExtraMaxLen int not null
    );

    INSERT Reporting101a.tOutput(tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra)
    SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME AS Field, COLUMN_TYPE AS TYPE, RPAD(IS_NULLABLE,4,' ') AS 'Null', 
    RPAD(COLUMN_KEY,3,' ') AS 'Key',RPAD(COLUMN_DEFAULT,7,' ') AS 'DEFAULT',EXTRA AS Extra
    FROM information_schema.columns WHERE table_schema = dbName ORDER BY table_name,ordinal_position; 
    -- select * from information_schema.columns WHERE table_schema = '57security' order by table_name,ordinal_position; 

    UPDATE Reporting101a.tOutput
    SET cExtra='     '
    WHERE cExtra='';

    UPDATE Reporting101a.tOutput
    SET cField=RPAD(cField,5,' ')
    WHERE LENGTH(cField)<5;

    INSERT Reporting101a.tOutput2(tblName,colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen,cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen)
    SELECT tblName,COUNT(*),0,0,0,0,0,0 
    FROM Reporting101a.tOutput 
    GROUP BY tblName;

    UPDATE tOutput2 t2
    JOIN
    (   SELECT tblName,MAX(LENGTH(cField)) AS mField,MAX(LENGTH(cType)) AS mType,MAX(LENGTH(cNull)) AS mNull,
        IFNULL(MAX(LENGTH(cKey)),0) AS mKey,IFNULL(MAX(LENGTH(cDefault)),0) AS mDefault,IFNULL(MAX(LENGTH(cExtra)),0) AS mExtra
        FROM Reporting101a.tOutput
        GROUP BY tblName
    ) x
    ON x.tblName=t2.tblName
    SET t2.cFieldMaxLen=x.mField,t2.cTypeMaxLen=x.mType,cNullMaxLen=x.mNull,
    cKeyMaxLen=x.mKey,cDefaultMaxLen=x.mDefault,cExtraMaxLen=x.mExtra;

    -- DROP TABLE Reporting101a.reportDataDefsSession; -- useful for quick change of structure of table
    -- note, keep above drop call remmed out ! Just use it for quick tweaks to structure
    CREATE TABLE IF NOT EXISTS Reporting101a.reportDataDefsSession
    (   -- for the sole purpose of safe session auto_inc usage
        -- Please don't delete unless you want the sessions to experience aberant behavior
        sessionId INT AUTO_INCREMENT PRIMARY KEY,
        dummy CHAR(1) NOT NULL,
        creationDT datetime not null
    );

    CREATE TABLE IF NOT EXISTS Reporting101a.reportDataDefs
    (   sessionId INT NOT NULL,
        tblName VARCHAR(100) NOT NULL,  -- Tablename
        ordVal INT NOT NULL,    -- the "position number" of the Column
        cField VARCHAR(100) NOT NULL,   -- The Column
        cType VARCHAR(100) NOT NULL,    -- Datatype
        cNull VARCHAR(100) NOT NULL,    -- Nullability
        cKey VARCHAR(100) NOT NULL, -- Key info
        cDefault VARCHAR(100) NULL, -- Default value
        cExtra VARCHAR(100) NULL,   -- Extra output
        colCount INT NOT NULL,  -- the columns here and below are de-normalize data
        cFieldMaxLen INT NOT NULL,
        cTypeMaxLen INT NOT NULL,
        cNullMaxLen INT NOT NULL,
        cKeyMaxLen INT NOT NULL,
        cDefaultMaxLen INT NOT NULL,
        cExtraMaxLen INT NOT NULL
    );

    -- For lack of a better notion, we are calling calls "sessions". The programmer calls the
    -- First Stored Proc, and we call that a session after we get a unique next incrementing number.
    -- That number is the session #. House all output with that as a column value. This allows us to 
    -- move between stored procs, have safe output, have historical snapshots, and retain the data 
    -- via a session # for later use, whatever use.
    INSERT Reporting101a.reportDataDefsSession(dummy,creationDT) VALUES ('X',now());
    SET @mySession=LAST_INSERT_ID(); -- there it is, our session # (read the above paragraph)

    INSERT Reporting101a.reportDataDefs(sessionId,tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra,
    colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen,cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen)    
    SELECT @mySession,t1.tblName,t1.ordVal,t1.cField,t1.cType,t1.cNull,t1.cKey,t1.cDefault,t1.cExtra,
    t2.colCount,t2.cFieldMaxLen,t2.cTypeMaxLen,t2.cNullMaxLen,t2.cKeyMaxLen,t2.cDefaultMaxLen,t2.cExtraMaxLen 
    FROM Reporting101a.tOutput t1
    JOIN Reporting101a.tOutput2 t2
    ON t2.tblName=t1.tblName
    ORDER BY t1.tblName,t1.id;

    DROP TEMPORARY TABLE Reporting101a.tOutput;
    DROP TEMPORARY TABLE Reporting101a.tOutput2;
    SET theSession=@mySession; -- the OUT var that came in as a parameter

    -- ***************************************************************************
    -- ***************************************************************************
    -- Label "Some_Sort_of_Output":
    IF callTheSecondStoredProc=TRUE THEN
        -- The caller says to call the second stored proc (for Pretty Printing)
        -- This will generate output similar to `DESCRIBE myTable`
        -- But remember, it will do it  for EVERY table in referenced database
        CALL Reporting101a.`Print_Tables_Like_Describe`(@mySession);
        -- The above call just gave you output.
    ELSE
        -- The caller chose to not auto call the Pretty Printing second stored procedure.
        -- Note, the caller can easily call it right after using the OUT parameter.
        -- So our output will be a resultset of out reportDataDefs table for this session #
        SELECT * 
        FROM Reporting101a.reportDataDefs 
        WHERE sessionId=@mySession
        ORDER BY tblName,ordVal;
    END IF;
    -- ***************************************************************************
    -- ***************************************************************************

    IF deleteSessionRows=TRUE THEN
        -- The caller says output rows are NOT needed at this point. Delete them.
        -- Note, if this boolean comes in TRUE, you can't call Pretty Printing
        -- second stored procedure with the session # because the data is gone.
        --
        -- Regardless, you are getting something back from "Some_Sort_of_Output" above.
        DELETE FROM Reporting101a.reportDataDefs
        WHERE sessionId=@mySession;
    END IF;
END$$
DELIMITER ;

DROP PROCEDURE IF EXISTS `Reporting101a`.`Print_Tables_Like_Describe`;
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `Reporting101a`.`Print_Tables_Like_Describe`(
    pSessionId INT
)
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE curTable VARCHAR(100) DEFAULT '';
    DECLARE bFirst BOOL DEFAULT TRUE;

    DECLARE lv_tblName,lv_cField,lv_cType,lv_cNull,lv_cKey,lv_cDefault,lv_cExtra VARCHAR(100);
    DECLARE lv_ordVal,lv_colCount,lv_cFieldMaxLen,lv_cTypeMaxLen,lv_cNullMaxLen,lv_cKeyMaxLen,lv_cDefaultMaxLen,lv_cExtraMaxLen INT;

    DECLARE cur1 CURSOR FOR SELECT tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra,
    colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen,cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen 
    FROM Reporting101a.reportDataDefs
    WHERE sessionId=pSessionId
    ORDER BY tblName,ordVal;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    -- Please note in the above, CURSOR stuff must come last else "Error 1337: Variable or condition decl aft curs" 

    CREATE TABLE IF NOT EXISTS Reporting101a.reportOutput
    (   lineNum INT AUTO_INCREMENT PRIMARY KEY,
        sessionId INT NOT NULL,
        lineOut varchar(100) NOT NULL
    );

    -- INSERT Reporting101a.reportOutput(sessionId,lineOut)
    -- SELECT 
    -- SET curTable='';
    DELETE FROM Reporting101a.reportOutput
    WHERE sessionId=pSessionId;

    OPEN cur1;

    read_loop: LOOP
        FETCH cur1 INTO lv_tblName,lv_ordVal,lv_cField,lv_cType,lv_cNull,lv_cKey,lv_cDefault,lv_cExtra,
            lv_colCount,lv_cFieldMaxLen,lv_cTypeMaxLen,lv_cNullMaxLen,lv_cKeyMaxLen,lv_cDefaultMaxLen,lv_cExtraMaxLen ;
        IF done THEN
            LEAVE read_loop;
        END IF;
        IF lv_tblName<>curTable THEN
            IF bFirst=FALSE THEN
                INSERT Reporting101a.reportOutput(sessionId,lineOut)
                SELECT pSessionId,'';
            ELSE
                SET bFirst=FALSE;
            END IF;
            INSERT Reporting101a.reportOutput(sessionId,lineOut)
            SELECT pSessionId,lv_tblName;
            INSERT Reporting101a.reportOutput(sessionId,lineOut)
            SELECT pSessionId,CONCAT('+-', 
                REPEAT('-',GREATEST(5,lv_cFieldMaxLen)),  '-+-',
                REPEAT('-',GREATEST(4,lv_cTypeMaxLen)), '-+-',
                REPEAT('-',GREATEST(4,lv_cNullMaxLen)), '-+-',
                REPEAT('-',GREATEST(3,lv_cKeyMaxLen)),  '-+-',
                REPEAT('-',GREATEST(7,lv_cDefaultMaxLen)),  '-+-',
                REPEAT('-',GREATEST(5,lv_cExtraMaxLen)),    '-+');

            SET @dashLineNumRow=LAST_INSERT_ID();

            INSERT Reporting101a.reportOutput(sessionId,lineOut)
            SELECT pSessionId,CONCAT('| ', 
                'Field',
                REPEAT(' ',GREATEST(0,lv_cFieldMaxLen-5)),  ' | ',
                'Type',
                REPEAT(' ',GREATEST(0,lv_cTypeMaxLen-4)),   ' | ',
                'Null',
                REPEAT(' ',GREATEST(0,lv_cNullMaxLen-4)),   ' | ',
                'Key',
                REPEAT(' ',GREATEST(0,lv_cKeyMaxLen-3)),    ' | ',
                'Default',
                REPEAT(' ',GREATEST(0,lv_cDefaultMaxLen-7)),    ' | ',
                'Extra',
                REPEAT(' ',GREATEST(0,lv_cExtraMaxLen-5)),  ' |');

            INSERT Reporting101a.reportOutput(sessionId,lineOut)
            SELECT pSessionId,lineOut
            FROM Reporting101a.reportOutput
            WHERE lineNum=@dashLineNumRow;

            -- SELECT * FROM Reporting101a.reportDataDefs WHERE sessionId=24;
            SET curTable=lv_tblName;
        END IF;
        INSERT Reporting101a.reportOutput(sessionId,lineOut)
        SELECT pSessionId,
            CONCAT('| ', 
            COALESCE(lv_cField,''),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cFieldMaxLen-LENGTH(lv_cField))),''),' | ',
            COALESCE(lv_cType,''),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cTypeMaxLen-LENGTH(lv_cType))),''),' | ',
            COALESCE(lv_cNull,''),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cNullMaxLen-LENGTH(lv_cNull))),''),' | ',
            COALESCE(lv_cKey,'   '),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cKeyMaxLen-LENGTH(lv_cKey))),''),' | ',
            COALESCE(lv_cDefault,'       '),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cDefaultMaxLen-LENGTH(lv_cDefault))),''),' | ',
            COALESCE(lv_cExtra,'     '),
            COALESCE(REPEAT(' ',GREATEST(0,lv_cExtraMaxLen-LENGTH(lv_cExtra))),''),' |');
        INSERT Reporting101a.reportOutput(sessionId,lineOut)
        SELECT pSessionId,lineOut
        FROM Reporting101a.reportOutput
        WHERE lineNum=@dashLineNumRow;
    END LOOP;
    CLOSE cur1;

    select lineOut as '' from Reporting101a.reportOutput where sessionId=pSessionId order by lineNum;
END$$
DELIMITER ;

测试

测试:

-- See **Note2**
SET @theOutVar =-1; -- A variable used as the OUT variable below

-- See **Note3**
-- Note: with `TRUE` as the 4th parameter, this is a one call deal. Meaning, you are done.
call Reporting101a.describeTables_v2a('Whosebug',@theOutVar,false,true);

-- See **Note4**
-- Primarily used if the 4th parameter above is false
call Reporting101a.Print_Tables_Like_Describe(@theOutVar); -- loads data for prettier results in chunk format.

输出

+--------------------------------------------------------------------------------------------+
|                                                                                    |
+--------------------------------------------------------------------------------------------+
| course                                                                                     |
| +------------+--------------+------+-----+---------+----------------+                      |
| | Field      | Type         | Null | Key | Default | Extra          |                      |
| +------------+--------------+------+-----+---------+----------------+                      |
| | courseId   | int(11)      | NO   | PRI |         | auto_increment |                      |
| +------------+--------------+------+-----+---------+----------------+                      |
| | deptId     | int(11)      | NO   | MUL |         |                |                      |
| +------------+--------------+------+-----+---------+----------------+                      |
| | courseName | varchar(100) | NO   |     |         |                |                      |
| +------------+--------------+------+-----+---------+----------------+                      |
|                                                                                            |
| dept                                                                                       |
| +----------+--------------+------+-----+---------+----------------+                        |
| | Field    | Type         | Null | Key | Default | Extra          |                        |
| +----------+--------------+------+-----+---------+----------------+                        |
| | deptId   | int(11)      | NO   | PRI |         | auto_increment |                        |
| +----------+--------------+------+-----+---------+----------------+                        |
| | deptName | varchar(100) | NO   |     |         |                |                        |
| +----------+--------------+------+-----+---------+----------------+                        |
|                                                                                            |
| scjunction                                                                                 |
| +------------+---------+------+-----+---------+----------------+                           |
| | Field      | Type    | Null | Key | Default | Extra          |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | id         | int(11) | NO   | PRI |         | auto_increment |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | studentId  | int(11) | NO   | MUL |         |                |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | courseId   | int(11) | NO   | MUL |         |                |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | term       | int(11) | NO   |     |         |                |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | attendance | int(11) | NO   |     |         |                |                           |
| +------------+---------+------+-----+---------+----------------+                           |
| | grade      | int(11) | NO   |     |         |                |                           |
| +------------+---------+------+-----+---------+----------------+                           |
|                                                                                            |
| student                                                                                    |
| +-----------+--------------+------+-----+---------+----------------+                       |
| | Field     | Type         | Null | Key | Default | Extra          |                       |
| +-----------+--------------+------+-----+---------+----------------+                       |
| | studentId | int(11)      | NO   | PRI |         | auto_increment |                       |
| +-----------+--------------+------+-----+---------+----------------+                       |
| | fullName  | varchar(100) | NO   |     |         |                |                       |
| +-----------+--------------+------+-----+---------+----------------+                       |
|                                                                                            |
| testtable                                                                                  |
| +-----------------------------------------+---------------+------+-----+---------+-------+ |
| | Field                                   | Type          | Null | Key | Default | Extra | |
| +-----------------------------------------+---------------+------+-----+---------+-------+ |
| | noPKhere                                | int(11)       | NO   |     |         |       | |
| +-----------------------------------------+---------------+------+-----+---------+-------+ |
| | veryLongColumnName_And_Then.Some_%_More | decimal(12,2) | YES  |     |         |       | |
| +-----------------------------------------+---------------+------+-----+---------+-------+ |
| | limit                                   | int(11)       | NO   |     |         |       | |
| +-----------------------------------------+---------------+------+-----+---------+-------+ |
|                                                                                            |
| testtable2                                                                                 |
| +-------+---------+------+-----+---------+-------+                                         |
| | Field | Type    | Null | Key | Default | Extra |                                         |
| +-------+---------+------+-----+---------+-------+                                         |
| | id    | int(11) | NO   | PRI |         |       |                                         |
| +-------+---------+------+-----+---------+-------+                                         |
+--------------------------------------------------------------------------------------------+

Note1: 创建了一个名为 Reporting101a 的数据库来容纳两个存储过程和一些支持 tables。这些例程首先调用一个存储过程,该存储过程引用数据库 以使用字符串在 上进行报告。

生成输出的数据是通过特殊的 INFORMATION_SCHEMA 数据库以只读安全方式访问的。因此,未触及正在报告的数据库。

此数据库中保存了三个非临时 table。

  1. reportDataDefsSession - 用于获取会话的简单 table#
  2. reportDataDefs - 从 INFORMATION_SCHEMA 返回的数据并进行了一些修改。它是基于会话的。
  3. reportOutput - 像 MySQL 的 DESCRIBE 一样用于打印的 table。它只是一个 table 用于将输出放在一起。它是基于会话的。

Note2:此 INT 变量作为 OUT 参数目标包含在内,写入并允许您在第一个存储过程准备数据。它代表一个会话 # 隔离输出以供以后报告。

某些环境(例如 PHP)具有某些技巧,使其成为某些程序员的阻碍。因此,如果您需要自己组合这两个存储过程,那么就这样做(如果您感到困惑,请单独询问我)。

无论如何,它显示了数据或努力如何将存储过程调用链接在一起。

老实说 我提出会话 # 作为 OUT 参数的主要原因之一是我知道我必须创建一个 CURSOR 才能获得漂亮的输出。这需要在第二个存储过程的顶部使用 Cursor DECLARE。并且 DECLAREs 必须出现在存储过程的顶部。所以束手无策,我走了这条路。

注3:这是对第一个存储过程的调用。很可能您将在此调用后将 TRUE 作为您的第 4 个参数完成。存储过程在其中有很好的记录。第三个参数用于确定是否要从会话 # 的报告 table 中删除数据。删除发生在作为结果集的任何输出之后。所以,这取决于你的选择。

参数:

  1. 用于描述所有 table 的数据库名称,如 describe myTable
  2. INTOUT参数来保持会话#
  3. boolean: 是否要在报告table结尾处删除数据
  4. boolean:我们是否应该自动调用生成类似 describe 输出的漂亮打印存储过程。如果您决定将参数 4 作为 FALSE 传递,那么您的输出可能类似于:

Note4:用于您想要不同的输出但希望会话 # 可以使用的情况。你通常不需要这个。