2016-08-01 52 views
16

如何显示类似于DESCRIBE myTable等输出的数据库中的所有表。增加功能为:在一次 显示所有表格。描述性功能

  • Tablesize
  • 字符集和校对信息
  • 排序功能
    • 所有表

    注:DESCRIBE输出是简单,在一个单一的表一次。

    编辑:

    从里克詹姆斯尼斯反馈。我不知所措,需要这种头脑风暴。

    如果有人想在每个表的底部

    • 指数(每个指数也许1行显示的名字和列名被分开添加功能(对我自信心的答案),如标示行逗号
    • 基数上指标线之上
    • 外键约束
    • 任何武器达成否则你的同龄人可能会发现有用
    • 有这整个街区被称为“扩展信息“的概念,并为Yay或Nay制作一个开关(一个参数)。如果'N'则不生成它。

    我会很高兴。自然,信息不会挂在我已经在自我回答中显示的列标题下。所以,一些视觉像缩进是立即想到的,而不是它的完整部分。粗糙的输出很好。

    考虑以下粗糙指出,可能的援助:

    create schema x99; 
    use x99; 
    
    create table parent 
    ( -- assume your have only one parent, ok bad example, it's early 
        id int auto_increment primary key, 
        fullName varchar(100) not null 
    )ENGINE=InnoDB; 
    
    -- drop table child; 
    create table child 
    ( id int auto_increment primary key, 
        fullName varchar(100) not null, 
        myParent int not null, 
        CONSTRAINT `mommy_daddy` FOREIGN KEY (myParent) REFERENCES parent(id) 
         ON DELETE CASCADE ON UPDATE CASCADE  
    )ENGINE=InnoDB; 
    
    create table t3 
    ( id INT AUTO_INCREMENT PRIMARY KEY, 
        myD DATE NOT NULL, 
        myI INT NOT NULL, 
        KEY `t3_001` (myD,myI) 
    ); 
    
    create table t4 
    ( someCode CHAR(4) PRIMARY KEY, 
        codeDescr VARCHAR(500) NOT NULL 
    ); 
    
    create table t5 
    ( id INT AUTO_INCREMENT PRIMARY KEY, 
        theCode CHAR(4) NOT NULL, 
        d1 DATE NOT NULL, 
        i1 INT NOT NULL, 
        someOther DATETIME NOT NULL, 
        FOREIGN KEY `cd_2_t4` (theCode) REFERENCES t4(someCode), 
        FOREIGN KEY `cd_2_t3` (d1,i1) REFERENCES t3(myD,myI) 
    ); 
    
    -- The below 2 lines are merely to show cardinality which I am sure is 
    -- read from INFO SCHEMA too 
    show indexes in child; -- to pick up cardinality (or from INFO SCHEMA) 
    show indexes in t5; -- ditto 
    -- So, I am not suggesting to actually call "show indexes" 
    
    
    -- http://dev.mysql.com/doc/refman/5.7/en/key-column-usage-table.html 
    -- James Goatcher 
    SELECT CONCAT(table_name, '.', 
    column_name, ' -> ', 
    referenced_table_name, '.', 
    referenced_column_name) AS list_of_fks 
    FROM information_schema.KEY_COLUMN_USAGE 
    WHERE REFERENCED_TABLE_SCHEMA = 'x99' 
    AND REFERENCED_TABLE_NAME is not null 
    ORDER BY TABLE_NAME, COLUMN_NAME; 
    +-----------------------------+ 
    | list_of_fks     | 
    +-----------------------------+ 
    | child.myParent -> parent.id | 
    | t5.d1 -> t3.myD    | 
    | t5.i1 -> t3.myI    | 
    | t5.theCode -> t4.someCode | 
    +-----------------------------+ 
    
    Despite the output suggested by James Goatcher on that Webpage, 
    perhaps what would look better under table t5 as 2 lines: 
    
    t5.d1,i1 -> t3.myD,myI    <----- That there would be swell 
    t5.theCode -> t4.someCode 
    
    -- You may make the assumption that all tables are in the same schema 
    -- If they aren't and it blows up that is fine 
    
    drop schema x99; 
    

    我想这个奖项奖金。

    +1

    我在寻找改进,同行评议,其他建议。 – Drew

    +1

    还请注意,当涉及组合索引,引擎等时,“DESCRIBE”不完整。 –

    +0

    目标受众是什么?我通常对一组“SHOW CREATE TABLE”感到满意。 –

    回答

    14

    这扩大了给出的答案Here。它添加了字符集和排序列,并且在数据库和表级别上也是如此。包括准系统在两种选择上进行排序:按字母顺序排列,按表计算,计算方法类似于here。我仍然认为这个概念需要一些同行评议。 DBA here上的Rolando正在展示一种方法,而Rick James评论道。这不是一个简单的计算,也不会包含非静态数据,如TEXTBLOB s。因此,请随时改进此计算并分享。无论如何,如果按照“尺寸”,表格通常会以所需的排序顺序返回。因为它与InnoDB文件大小有关,所以我不保证它的准确性。

    它允许您为存根提高排序功能。例如,通过让另一个排序顺序表根据主表与支持表和代码表进行联接。

    会话:这依赖于会话的概念,它只是您调用例程的一个实例。把它们想象成快照可以稍后访问。该时间点的数据包含在会话快照中。当你改变表格时可能会有用。特别是整理。呵呵,关于排序规则,当开发人员从互联网上剪切和粘贴代码时(表级和列级字符集和排序规则不匹配),外键约束通常会因排序规则设置不正确而失败。这就是为什么我把它扔进这个版本。

    这个例程生存在一个数据库Reporting101a中,该数据库包含两个存储过程和一些支持表(几乎所有基于会话的表)。约5桌。

    调用示例:

    1. call Reporting101a.describeTables_v3('myDb',@theOutVar,false,true,'size')
    2. call Reporting101a.describeTables_v3('myDb',@theOutVar,false,true,'alpha')
    3. call Reporting101a.Print_Tables_Like_Describe(4,'size')

    注意事项】

    参数(第一个存储过程):

    1. 用于描述所有表的数据库名称。
    2. INTOUT参数举行会议#
    3. 布尔:你想在年底
    4. 布尔从报告表中删除的数据:我们是否应该自动调用生成describe般的漂亮打印存储过程输出。
    5. 排序:'大小'或'alpha'。事实上,除'大小'之外的任何东西都会导致'alpha'。

    参数(漂亮的打印存储过程):

    1. 会议之前#保存快照。
    2. 按上述排序。

    该代码是相当有据可查的,短把它变成600行的代码与400

    的例程是自包含的并且在Reporting101a数据库自引用。所以从任何地方明确地称呼他们

    注A:关于上面的例子:Ex。 1和2类似,只是不同的排序顺序。这些是您正常使用它的方式,只需拨打一个。表格大小总是显示在表格名称旁边。只有'大小'它是排序就可以了。第四个参数为True,它在最后自动调用Pretty Printing Stored Proc。否则,呈现简单的结果集。将写入@theOutVar,因为它代表创建的会话#。这对于稍后手动调用Pretty Printing存储过程非常有用,可以插入其中一个例程并使用这些数据,或者在几个月后(冻结的快照)重播结果。所以,Ex。 3是您希望基于之前的呼叫检索数据以输出数据,并已反馈Session#。例如前面提到的例子1和2(其中参数#4本应是,然而)。或者,如果您只是想重新报告之前的数据快照。

    建议用法是在通话结束后不要删除会话数据。因此,请将参数#3保留为False,意思是不要删除。

    这些例程不会以任何方式影响您的数据。它只修改数据库的数据库。

    输出:如果例程在命令行之外运行(例如在MySQL Workbench中),则表包装列将围绕为输出生成的所有表的全部内容。它有一个“'(空白字符串)的列标题。但它仍然相当烦人。这可见于输出1如下所示。但是,如果你的杠杆命令行switches-N -B(跳过列名和批处理模式),如通过以下调用:

    mysql -uYourDBUser -p -N -B -e "call Reporting101a.describeTables_v3('Sample011',@theOutVar,false,true,'size')" > sampleOut.txt 
    

    ...这将产生一个非包裹输出。更令人愉快。写入sampleOut.txt文件。见输出2以下。

    测试日期:5.55.6.315.7.13

    性能:它使用CURSORS漂亮打印。我通常会嘲笑这个概念。但考虑到这些是不经常的调用,并且一两分钟看起来可能是可以接受的,我很高兴地发现对于具有120个表的模式,性能低于10秒。在我的测试中,Linux比Windows要快得多。

    两个存储过程(包括在顶部的CREATE SCHEMA):

    CREATE SCHEMA IF NOT EXISTS `Reporting101a`; -- See **Note1** 
    
    DROP PROCEDURE IF EXISTS `Reporting101a`.`describeTables_v3`; 
    DELIMITER $$ 
    CREATE DEFINER=`root`@`localhost` PROCEDURE `Reporting101a`.`describeTables_v3`(
        IN pDBName 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 
        IN pOrderBy CHAR(20) -- 'ALPHA' OR 'SIZE'. Alphabetical order, or table size order(desc) 
    ) 
    BEGIN 
        DECLARE thisTable CHAR(100); 
        DECLARE beginDT,endDT DATETIME; 
    
        SET beginDT=NOW(); 
        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, 
         cCharSetName VARCHAR(100) NULL, 
         cCollName 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, 
         cCharSetNameMaxLen INT NOT NULL, 
         cCollNameMaxLen INT NOT NULL 
        ); 
    
        INSERT Reporting101a.tOutput(tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra,cCharSetName,cCollName) 
        SELECT TABLE_NAME,ORDINAL_POSITION,COLUMN_NAME,COLUMN_TYPE,RPAD(IS_NULLABLE,4,' '), 
        RPAD(COLUMN_KEY,3,' '),RPAD(COLUMN_DEFAULT,7,' '),EXTRA,CHARACTER_SET_NAME,COLLATION_NAME 
        FROM INFORMATION_SCHEMA.COLUMNS 
        WHERE table_schema = pDBName 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; 
    
        UPDATE Reporting101a.tOutput 
        SET cCharSetName=RPAD(COALESCE(cCharSetName,''),8,' ') 
        WHERE LENGTH(COALESCE(cCharSetName,''))<8; 
    
        UPDATE Reporting101a.tOutput 
        SET cCollName=RPAD(COALESCE(cCollName,''),9,' ') 
        WHERE LENGTH(COALESCE(cCollName,''))<9; 
    
        INSERT Reporting101a.tOutput2(tblName,colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen, 
        cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen,cCharSetNameMaxLen,cCollNameMaxLen) 
        SELECT tblName,COUNT(*),0,0,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, 
         IFNULL(MAX(LENGTH(cCharSetName)),0) AS mCharSetName,IFNULL(MAX(LENGTH(cCollName)),0) AS mCollName 
         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,cCharSetNameMaxLen=x.mCharSetName,cCollNameMaxLen=x.mCollName; 
    
        CREATE TABLE IF NOT EXISTS Reporting101a.reportDataSessions 
        ( -- For the purpose of safe session auto_inc usage, timings, and rowcount 
         -- Please don't delete unless you want the sessions to experience aberrant behavior. 
         -- That is, the inability to report on prior sessions run. Which is no big deal. 
         sessionId INT AUTO_INCREMENT PRIMARY KEY, 
         dbName VARCHAR(100) NOT NULL, 
         -- character_set_name VARCHAR(100) NULL, 
         -- collation_name VARCHAR(100) NULL, 
         creationDT DATETIME NOT NULL, 
         partA_BeginDT DATETIME NULL, 
         partA_EndDT DATETIME NULL, -- See the following for fractional seconds: 
         partB_BeginDT DATETIME NULL, -- http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html 
         partB_EndDT DATETIME NULL, 
         rowCount INT NULL 
        ); 
    
        CREATE TABLE IF NOT EXISTS Reporting101a.reportDataColumns 
        ( 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 
         cCharSetName VARCHAR(100) NULL, -- Default value 
         cCollName 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, 
         cCharSetNameMaxLen INT NOT NULL, 
         cCollNameMaxLen INT NOT NULL 
        ); 
    
        CREATE TABLE IF NOT EXISTS Reporting101a.reportDataTables 
        ( sessionId INT NOT NULL, 
         tblName VARCHAR(100) NOT NULL, -- tablename 
         character_set_name VARCHAR(100) NULL, -- table-level default char set 
         collation_name VARCHAR(100) NULL, -- table-level default collation 
         rowcount BIGINT NULL, -- rowcount (subject to system refresh, ditto, next column) 
         tblSizeMB DECIMAL(14,2) NULL -- in MB 
        ); 
    
        CREATE TABLE IF NOT EXISTS Reporting101a.reportDataDatabases 
        ( sessionId INT NOT NULL, 
         dbName VARCHAR(100) NOT NULL, -- Tablename 
         character_set_name VARCHAR(100) NULL, -- db-level default char set 
         collation_name VARCHAR(100) NULL -- db-level default collation 
        ); 
    
        -- 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.reportDataSessions(dbName,creationDT) VALUES (pDBName,now()); 
        SET @mySession=LAST_INSERT_ID(); -- there it is, our session # (read the above paragraph) 
    
        INSERT Reporting101a.reportDataColumns(sessionId,tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra,cCharSetName,cCollName, 
        colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen,cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen,cCharSetNameMaxLen,cCollNameMaxLen)  
        SELECT @mySession,t1.tblName,t1.ordVal,t1.cField,t1.cType,t1.cNull,t1.cKey,t1.cDefault,t1.cExtra,t1.cCharSetName,t1.cCollName, 
        t2.colCount,t2.cFieldMaxLen,t2.cTypeMaxLen,t2.cNullMaxLen,t2.cKeyMaxLen,t2.cDefaultMaxLen,t2.cExtraMaxLen,t2.cCharSetNameMaxLen,t2.cCollNameMaxLen 
        FROM Reporting101a.tOutput t1 
        JOIN Reporting101a.tOutput2 t2 
        ON t2.tblName=t1.tblName 
        ORDER BY t1.tblName,t1.id; 
    
        INSERT Reporting101a.reportDataTables(sessionId,tblName,character_set_name,collation_name,rowcount,tblSizeMB) 
        SELECT DISTINCT @mySession,tblName,NULL,NULL,NULL,NULL 
        FROM Reporting101a.reportDataColumns 
        WHERE [email protected]; 
    
        -- http://dev.mysql.com/doc/refman/5.7/en/collation-character-set-applicability-table.html 
        -- TLDR; A collation can map to a character set 
        UPDATE Reporting101a.reportDataTables rdt 
        JOIN INFORMATION_SCHEMA.`TABLES` ist 
        ON ist.TABLE_SCHEMA=pDBName AND ist.TABLE_NAME=rdt.tblName 
        JOIN INFORMATION_SCHEMA.`COLLATION_CHARACTER_SET_APPLICABILITY` isccsa 
        ON isccsa.COLLATION_NAME=ist.TABLE_COLLATION 
        SET rdt.character_set_name=isccsa.CHARACTER_SET_NAME,rdt.collation_name=isccsa.COLLATION_NAME, 
        rdt.rowcount=ist.TABLE_ROWS,rdt.tblSizeMB=round(((ist.data_length+ist.index_length)/1048576), 2) 
        WHERE [email protected]; 
    
        INSERT Reporting101a.reportDataDatabases(sessionId,dbName,character_set_name,collation_name) 
        SELECT @mySession,pDBName,DEFAULT_CHARACTER_SET_NAME,DEFAULT_COLLATION_NAME 
        FROM INFORMATION_SCHEMA.SCHEMATA 
        WHERE schema_name = pDBName; 
    
        DROP TEMPORARY TABLE Reporting101a.tOutput; 
        DROP TEMPORARY TABLE Reporting101a.tOutput2; 
        SET [email protected]; -- the OUT var that came in as a parameter 
        SET endDT=NOW(); 
        UPDATE Reporting101a.reportDataSessions 
        SET partA_BeginDT=beginDT,partA_EndDT=endDT 
        WHERE [email protected]; 
        -- *************************************************************************** 
        -- *************************************************************************** 
        -- 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,pOrderBy); 
         -- 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 reportDataColumns table for this session # 
         IF pOrderBy!='size' THEN 
          -- Order by Alpha for any parameter except 'size' 
          SELECT * 
          FROM Reporting101a.reportDataColumns 
          WHERE [email protected] 
          ORDER BY tblName,ordVal; 
         ELSE 
          -- Order By size DESC 
          SELECT rdc.* 
          FROM Reporting101a.reportDataTables rdt 
          JOIN Reporting101a.reportDataColumns rdc 
          ON rdc.tblName=rdt.tblName and rdc.sessionId=rdt.sessionId 
          WHERE [email protected] 
          ORDER BY rdt.tblSizeMB DESC,rdc.tblName,rdc.ordVal; 
         END IF; 
        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.reportDataColumns 
         WHERE [email protected]; 
    
         DELETE FROM Reporting101a.reportDataTables 
         WHERE [email protected]; 
    
         -- Do not delete the row from the Sessions table for now (you can, I'm not atm) 
        END IF; 
    END$$ 
    DELIMITER ; 
    
    -- ***************************************************************** 
    -- ***************************************************************** 
    -- ***************************************************************** 
    
    DROP PROCEDURE IF EXISTS `Reporting101a`.`Print_Tables_Like_Describe`; 
    DELIMITER $$ 
    CREATE DEFINER=`root`@`localhost` PROCEDURE `Reporting101a`.`Print_Tables_Like_Describe`(
        IN pSessionId INT, 
        IN pOrderBy CHAR(20) -- 'size' or 'alpha' (see CURSORs below). Size means Tablesize (see ____). 
    ) 
    BEGIN 
        -- Please note: CURSOR stuff must come last in DECLAREs, else "Error 1337: Variable or condition decl aft curs" 
        DECLARE beginDT,EndDT DATETIME; 
        DECLARE done INT DEFAULT FALSE; 
        DECLARE curTable VARCHAR(100) DEFAULT ''; 
        DECLARE bFirst BOOL DEFAULT TRUE; 
        DECLARE lv_dbName,CharSetName,CollationName,someClueToCaller VARCHAR(100); 
        DECLARE lv_rowCount,lineCount INT; 
        DECLARE theSize DECIMAL(14,2); 
        DECLARE lv_sessionDT DATETIME; 
        DECLARE lv_tblName,lv_cField,lv_cType,lv_cNull,lv_cKey,lv_cDefault,lv_cExtra,lv_cCharSetName,lv_cCollName VARCHAR(100); 
        DECLARE lv_ordVal,lv_colCount,lv_cFieldMaxLen,lv_cTypeMaxLen,lv_cNullMaxLen,lv_cKeyMaxLen, 
        lv_cDefaultMaxLen,lv_cExtraMaxLen,lv_cCharSetNameMaxLen,lv_cCollNameMaxLen INT; 
        -- ------------------------------------------------------------------------------------------------------------------- 
        -- The below cursor is in Alphabetical Ascending order 
        DECLARE curAlpha CURSOR FOR SELECT tblName,ordVal,cField,cType,cNull,cKey,cDefault,cExtra,cCharSetName,cCollName, 
        colCount,cFieldMaxLen,cTypeMaxLen,cNullMaxLen,cKeyMaxLen,cDefaultMaxLen,cExtraMaxLen,cCharSetNameMaxLen,cCollNameMaxLen 
        FROM Reporting101a.reportDataColumns 
        WHERE rdt.sessionId=pSessionId 
        ORDER BY tblName,ordVal; -- ascending order by tablename then the ordinal position of each column (1..n) 
    
        -- The below cursor is in Tablesize Descending order, followed by tablename + ordinal position ascending 
        DECLARE curSize CURSOR FOR SELECT rdc.tblName,rdc.ordVal,rdc.cField,rdc.cType,rdc.cNull,rdc.cKey,rdc.cDefault, 
        rdc.cExtra,rdc.cCharSetName,rdc.cCollName,rdc.colCount,rdc.cFieldMaxLen,rdc.cTypeMaxLen,rdc.cNullMaxLen, 
        rdc.cKeyMaxLen,rdc.cDefaultMaxLen,rdc.cExtraMaxLen,rdc.cCharSetNameMaxLen,rdc.cCollNameMaxLen 
        FROM Reporting101a.reportDataTables rdt 
        JOIN Reporting101a.reportDataColumns rdc 
        ON rdc.tblName=rdt.tblName and rdc.sessionId=rdt.sessionId 
        WHERE rdt.sessionId=pSessionId 
        ORDER BY rdt.tblSizeMB DESC,rdc.tblName,rdc.ordVal; -- tablesize desc, then tablename + ordinal position ascending 
    
        -- What is the Ordinal Position? Simply 1..n as saved in the db 
        -- (see ORDINAL_POSITION in INFORMATION_SCHEMA.COLUMNS) 
        -- 
        -- If it is terribly bothersome, then look into 
        -- "ALTER TABLE" and use FIRST or AFTER .. :) 
    
        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" 
        -- ------------------------------------------------------------------------------------------------------------------- 
        SET beginDT=NOW(); 
        SET lineCount=0; 
        CREATE TABLE IF NOT EXISTS Reporting101a.reportOutput 
        ( lineNum INT AUTO_INCREMENT PRIMARY KEY, 
         sessionId INT NOT NULL, 
         lineOut varchar(200) NOT NULL 
        ); 
    
        DELETE FROM Reporting101a.reportOutput WHERE sessionId=pSessionId; -- cleans up a prior run with this session# 
    
        IF pOrderBy!='size' THEN 
         OPEN curAlpha; -- we are in using the Alphabetical Cursor (includes typos from caller for the sort column) 
        ELSE 
         OPEN curSize; -- we are in using the Tablesize Cursor 
        END IF; 
    
        -- **Place004** (Top-most output, Session #, then get top-level database info, there is not much of it) 
        -- Here is the importance of it though: it documents the state of things at that point in time 
        -- And it allows for reporting later by using that Session # (so that is why a Session # should hang out and remain) 
        -- So, a snapshot. You don't even need to print and use the output now. You can have it for later. To compare. 
        SELECT creationDT INTO lv_sessionDT FROM Reporting101a.reportDataSessions WHERE sessionId=pSessionId; 
    
        SET someClueToCaller='Typo from caller, using Alphabetical'; 
        IF pOrderBy='size' THEN 
         SET someClueToCaller='table size DESC'; 
        END IF; 
        IF pOrderBy='alpha' THEN 
         SET someClueToCaller='tablename alphabetical'; 
        END IF; 
        INSERT Reporting101a.reportOutput(sessionId,lineOut) 
        SELECT pSessionId,CONCAT('Session: ', pSessionId, ', Date:',lv_sessionDT,' , SortOrder: ',someClueToCaller); 
    
        INSERT Reporting101a.reportOutput(sessionId,lineOut) VALUES (pSessionId,''); -- blank line 
    
        SELECT dbName,character_set_name,collation_name INTO lv_dbName,CharSetName,CollationName 
        FROM Reporting101a.reportDataDatabases 
        WHERE sessionId=pSessionId; 
    
        INSERT Reporting101a.reportOutput(sessionId,lineOut) 
        SELECT pSessionId,CONCAT('Database: ', lv_dbname, ' (CharSet=', COALESCE(CharSetName,''), ', Collation=', COALESCE(CollationName,''), ')'); 
    
        INSERT Reporting101a.reportOutput(sessionId,lineOut) VALUES (pSessionId,''); -- blank line 
        -- end **Place004** ---------------------------------------------------------------------- 
    
    
        read_loop: LOOP 
         IF pOrderBy!='size' THEN 
          FETCH curAlpha INTO lv_tblName,lv_ordVal,lv_cField,lv_cType,lv_cNull,lv_cKey,lv_cDefault,lv_cExtra,lv_cCharSetName, 
          lv_cCollName,lv_colCount,lv_cFieldMaxLen,lv_cTypeMaxLen,lv_cNullMaxLen,lv_cKeyMaxLen,lv_cDefaultMaxLen, 
          lv_cExtraMaxLen,lv_cCharSetNameMaxLen,lv_cCollNameMaxLen ; 
         ELSE 
          FETCH curSize INTO lv_tblName,lv_ordVal,lv_cField,lv_cType,lv_cNull,lv_cKey,lv_cDefault,lv_cExtra,lv_cCharSetName, 
          lv_cCollName,lv_colCount,lv_cFieldMaxLen,lv_cTypeMaxLen,lv_cNullMaxLen,lv_cKeyMaxLen,lv_cDefaultMaxLen, 
          lv_cExtraMaxLen,lv_cCharSetNameMaxLen,lv_cCollNameMaxLen ; 
         END IF; 
         IF done THEN 
          LEAVE read_loop; 
         END IF; 
         IF lv_tblName<>curTable THEN -- **Place006**, "the IF" 
          -- We stumbled into a "This is a New table condition (different table) 
          -- So we need to create the New Chunk Header Info (also get table-level info like rowcount etc ie **Place7** below) 
          -- (as opposed to just displaying the next column info on a table we were already working with) 
          IF bFirst=FALSE THEN 
           INSERT Reporting101a.reportOutput(sessionId,lineOut) 
           SELECT pSessionId,''; -- Insert a blank line between tables (but not the first time) 
          ELSE 
           SET bFirst=FALSE; 
          END IF; 
    
          -- **Place007** (get top-level table info, there is not much of it, just, like, rowcount, charset, collation) 
          SELECT rowcount,character_set_name,collation_name,tblSizeMB INTO lv_rowCount,CharSetName,CollationName,theSize 
          FROM Reporting101a.reportDataTables 
          WHERE sessionId=pSessionId AND tblName=lv_tblName; 
    
          INSERT Reporting101a.reportOutput(sessionId,lineOut) 
          SELECT pSessionId,CONCAT(lv_tblName,' (rowcount=',ifnull(lv_rowCount,0),') (Size=',theSize,'MB) (CharSet=',COALESCE(CharSetName,''), ', Collation=',COALESCE(CollationName,''),')'); 
          -- end **Place007** ---------------------------------------------------------------------- 
    
    
          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)), '-+-', 
           REPEAT('-',GREATEST(8,lv_cCharSetNameMaxLen)),'-+-', 
           REPEAT('-',GREATEST(5,lv_cCollNameMaxLen)), '-+'); 
    
          SET @dashLineNumRow=LAST_INSERT_ID(); -- **Place008**: Save this row id so we can use it again in one sec 
    
          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)), ' | ', 
           'Char Set', 
           REPEAT(' ',GREATEST(0,lv_cCharSetNameMaxLen-8)), ' | ', 
           'Collation', 
           REPEAT(' ',GREATEST(0,lv_cCollNameMaxLen-9)), ' |'); 
    
          INSERT Reporting101a.reportOutput(sessionId,lineOut) 
          SELECT pSessionId,lineOut FROM Reporting101a.reportOutput 
          WHERE [email protected]; -- related to **Place008** above (just repeat it to close-off header) 
    
          SET curTable=lv_tblName; -- set the variable which is our flag for Next/New/Different table (related: **Place006** above) 
         END IF; 
    
         -- The below is the generic insert for a column's info 
         INSERT Reporting101a.reportOutput(sessionId,lineOut) 
         SELECT pSessionId, 
          CONCAT('| ', 
          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))),''),' | ', 
          lv_cCharSetName, 
          REPEAT(' ',GREATEST(0,lv_cCharSetNameMaxLen-LENGTH(lv_cCharSetName))),' | ', 
          lv_cCollName, 
          REPEAT(' ',GREATEST(0,lv_cCollNameMaxLen-LENGTH(lv_cCollName))),' |'); 
         SET lineCount=lineCount+1; -- increment only for column rows not separator rows 
         INSERT Reporting101a.reportOutput(sessionId,lineOut) 
         SELECT pSessionId,lineOut 
         FROM Reporting101a.reportOutput 
         WHERE [email protected]; 
        END LOOP; 
        IF pOrderBy!='size' THEN 
         CLOSE curAlpha; 
        ELSE 
         CLOSE curSize; 
        END IF; 
    
        SET endDT=NOW(); 
    
        UPDATE Reporting101a.reportDataSessions 
        SET partB_BeginDT=beginDT,partB_EndDT=endDT,rowCount=lineCount 
        WHERE sessionId=pSessionId; 
    
        SELECT lineOut AS '' from Reporting101a.reportOutput WHERE sessionId=pSessionId ORDER BY lineNum; 
        -- Note: The whole outer box wrapper is suppressed (which is cool) if we perform a 
        -- 
        -- OSPrompt> mysql -N -B -u UserName -p -e "call Reporting101a.describeTables_v3('stackoverflow',@theOutVar,false,true,'size')" 
        -- 
        -- That above -N -B suppresses column info (-N), ... (-B) keeps the output left aligned and is Batch mode 
        -- I understand (-N), but without (-B) the alignment goes right-aligned 
        -- Regardless, it allows us to perform what would appear to 
        -- be merely PRINT statements, if you will. No outer box wrapper in output. 
    END$$ 
    DELIMITER ; 
    

    输出1(示出包裹/外含表)。两个黄色荧光笔片是表名。

    enter image description here

    其中移除外包裹表输出2(使用-N -B开关命令行)。请参阅上面的示例输出部分的使用。有效的允许在MySQL中使用PRINT命令。

    enter image description here

    +2

    所有事情都发生在闪存中!:p – 1000111

    +0

    如果你有很多表,查询可能会很慢。他们必须有效地打开每一张桌子。 (5.8的内置数据字典将解决这个问题。) –

    +0

    请记住,rowcount是InnoDB表的近似值。 –