How can I get the table description (fields and types) from Firebird with dbExpress

后端 未结 4 1809
你的背包
你的背包 2021-02-04 07:42

I have written a tool for displaying database structures using the GetTableNames and GetFieldNames methods of TSQLConnection. How can I get the types of each field name similar

相关标签:
4条回答
  • 2021-02-04 07:59

    Use direct access to RDB$ tables. For example:

    SELECT * FROM rdb$relations
    

    will give you a list of all tables in a database.

    SELECT
      *
    FROM
      rdb$relation_fields rf JOIN rdb$fields f
        ON f.rdb$field_name = rf.rdb$field_source
    WHERE
      rf.rdb$relation_name = :RN
    

    will result in a list of all fields of given table with information of field type. Param RN is a name of the table.

    Using information from RDB$tables one can easily construct DDL statement. The query below gives you a hint how to do it:

    SELECT
      TRIM(rf.rdb$field_name) || ' ' ||
      IIF(rdb$field_source LIKE 'RDB$%',
      DECODE(f.rdb$field_type, 
        8,  'INTEGER', 
        12, 'DATE', 
        37, 'VARCHAR', 
        14, 'CHAR', 
        7,  'SMALLINT'),
      TRIM(rdb$field_source)) ||
      IIF((rdb$field_source LIKE 'RDB$%') AND (f.rdb$field_type IN (37, 14)),
        '(' || f.rdb$field_length || ')',
        '') ||
      IIF((f.rdb$null_flag = 1) OR (rf.rdb$null_flag = 1), 
        ' NOT NULL', '')
    FROM
      rdb$relation_fields rf JOIN rdb$fields f
        ON f.rdb$field_name = rf.rdb$field_source
    WHERE
      rf.rdb$relation_name = '<put_your_table_name_here>'
    
    0 讨论(0)
  • 2021-02-04 08:05

    I made a litle change to the first option to support computed by fields, add field_position and made a view to make more easy.

    CREATE VIEW TABLES (
      TABLE_NAME,
      FIELD_NAME,
      FIELD_POSITION,
      FIELD_TYPE,
      FIELD_NULL,
      FIELD_CHARSET,
      FIELD_COLLATION,
      FIELD_DEFAULT,
      FIELD_CHECK,
      FIELD_DESCRIPTION
    )
    AS
    SELECT
      RF.RDB$RELATION_NAME,
      RF.RDB$FIELD_NAME FIELD_NAME,
      RF.RDB$FIELD_POSITION FIELD_POSITION,
      CASE F.RDB$FIELD_TYPE
        WHEN 7 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'SMALLINT'
            WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 8 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'INTEGER'
            WHEN 1 THEN 'NUMERIC('  || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 9 THEN 'QUAD'
        WHEN 10 THEN 'FLOAT'
        WHEN 12 THEN 'DATE'
        WHEN 13 THEN 'TIME'
        WHEN 14 THEN 'CHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ') '
        WHEN 16 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'BIGINT'
            WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 27 THEN 'DOUBLE'
        WHEN 35 THEN 'TIMESTAMP'
        WHEN 37 THEN
         IIF (COALESCE(f.RDB$COMPUTED_SOURCE,'')<>'',
          'COMPUTED BY ' || CAST(f.RDB$COMPUTED_SOURCE AS VARCHAR(250)),
          'VARCHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')')
        WHEN 40 THEN 'CSTRING' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
        WHEN 45 THEN 'BLOB_ID'
        WHEN 261 THEN 'BLOB SUB_TYPE ' || F.RDB$FIELD_SUB_TYPE
        ELSE 'RDB$FIELD_TYPE: ' || F.RDB$FIELD_TYPE || '?'
      END FIELD_TYPE,
      IIF(COALESCE(RF.RDB$NULL_FLAG, 0) = 0, NULL, 'NOT NULL') FIELD_NULL,
      CH.RDB$CHARACTER_SET_NAME FIELD_CHARSET,
      DCO.RDB$COLLATION_NAME FIELD_COLLATION,
      COALESCE(RF.RDB$DEFAULT_SOURCE, F.RDB$DEFAULT_SOURCE) FIELD_DEFAULT,
      F.RDB$VALIDATION_SOURCE FIELD_CHECK,
      RF.RDB$DESCRIPTION FIELD_DESCRIPTION
    FROM RDB$RELATION_FIELDS RF
    JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE)
    LEFT OUTER JOIN RDB$CHARACTER_SETS CH ON (CH.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID)
    LEFT OUTER JOIN RDB$COLLATIONS DCO ON ((DCO.RDB$COLLATION_ID = F.RDB$COLLATION_ID) AND (DCO.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID))
    WHERE (COALESCE(RF.RDB$SYSTEM_FLAG, 0) = 0)
    ORDER BY RF.RDB$FIELD_POSITION
    ;
    
    0 讨论(0)
  • 2021-02-04 08:13

    Using the link which TLama provided, I found my own solution, which is somewhat similar to the above solutions, but simpler.

    SELECT R.RDB$FIELD_NAME AS field_name,
    CASE F.RDB$FIELD_TYPE
     WHEN 7 THEN 'SMALLINT'
     WHEN 8 THEN 'INTEGER'
     WHEN 9 THEN 'QUAD'
     WHEN 10 THEN 'FLOAT'
     WHEN 11 THEN 'D_FLOAT'
     WHEN 12 THEN 'DATE'
     WHEN 13 THEN 'TIME'     
     WHEN 14 THEN 'CHAR'
     WHEN 16 THEN 'INT64'
     WHEN 27 THEN 'DOUBLE'
     WHEN 35 THEN 'TIMESTAMP'
     WHEN 37 THEN 'VARCHAR'
     WHEN 40 THEN 'CSTRING'
     WHEN 261 THEN 'BLOB'
     ELSE 'UNKNOWN'
    END AS field_type,
    F.RDB$FIELD_LENGTH AS field_length,
    CSET.RDB$CHARACTER_SET_NAME AS field_charset
    FROM RDB$RELATION_FIELDS R
    LEFT JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME
    LEFT JOIN RDB$CHARACTER_SETS CSET ON F.RDB$CHARACTER_SET_ID = CSET.RDB$CHARACTER_SET_ID
    WHERE R.RDB$RELATION_NAME= :p1
    ORDER BY R.RDB$FIELD_POSITION
    

    p1 is the table name which is passed as a parameter to the query.

    In context, I have a treeview which has as its nodes the table names of a given database; for each node, the child nodes are the fields along with their definitions.

     sqlcon.GetTableNames (dbTables);    // sqlcon is the TSQLConnection
     tv.items.Clear;
     for i:= 1 to dbTables.count do
      begin
       node:= tv.items.Add (nil, dbTables[i - 1]);
       with qFields do                   // the above query
        begin
         params[0].asstring:= dbTables[i - 1];
         open;
         while not eof do
          begin
           tv.items.addchild (node, trim (fieldbyname ('field_name').asstring) + ', ' +
                                    trim (fieldbyname ('field_type').asstring) + ', ' +
                                    fieldbyname ('field_length').asstring + ', ' +
                                    fieldbyname ('field_charset').asstring);
           next
          end;
         close
        end
      end;
    

    Here is a screenshot of the program in action. I realise that the format is not the same as the DDL which I quoted, but it's obvious what each field means (at least to me, and this is a program for my private use).

    enter image description here

    0 讨论(0)
  • 2021-02-04 08:24

    This is incomplete (because I've never used Firebird array data types) and not much tested but perhaps it will give you a good starting point:

    SELECT
      RF.RDB$FIELD_NAME FIELD_NAME,
      CASE F.RDB$FIELD_TYPE
        WHEN 7 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'SMALLINT'
            WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 8 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'INTEGER'
            WHEN 1 THEN 'NUMERIC('  || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 9 THEN 'QUAD'
        WHEN 10 THEN 'FLOAT'
        WHEN 12 THEN 'DATE'
        WHEN 13 THEN 'TIME'
        WHEN 14 THEN 'CHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ') '
        WHEN 16 THEN
          CASE F.RDB$FIELD_SUB_TYPE
            WHEN 0 THEN 'BIGINT'
            WHEN 1 THEN 'NUMERIC(' || F.RDB$FIELD_PRECISION || ', ' || (-F.RDB$FIELD_SCALE) || ')'
            WHEN 2 THEN 'DECIMAL'
          END
        WHEN 27 THEN 'DOUBLE'
        WHEN 35 THEN 'TIMESTAMP'
        WHEN 37 THEN 'VARCHAR(' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
        WHEN 40 THEN 'CSTRING' || (TRUNC(F.RDB$FIELD_LENGTH / CH.RDB$BYTES_PER_CHARACTER)) || ')'
        WHEN 45 THEN 'BLOB_ID'
        WHEN 261 THEN 'BLOB SUB_TYPE ' || F.RDB$FIELD_SUB_TYPE
        ELSE 'RDB$FIELD_TYPE: ' || F.RDB$FIELD_TYPE || '?'
      END FIELD_TYPE,
      IIF(COALESCE(RF.RDB$NULL_FLAG, 0) = 0, NULL, 'NOT NULL') FIELD_NULL,
      CH.RDB$CHARACTER_SET_NAME FIELD_CHARSET,
      DCO.RDB$COLLATION_NAME FIELD_COLLATION,
      COALESCE(RF.RDB$DEFAULT_SOURCE, F.RDB$DEFAULT_SOURCE) FIELD_DEFAULT,
      F.RDB$VALIDATION_SOURCE FIELD_CHECK,
      RF.RDB$DESCRIPTION FIELD_DESCRIPTION
    FROM RDB$RELATION_FIELDS RF
    JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE)
    LEFT OUTER JOIN RDB$CHARACTER_SETS CH ON (CH.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID)
    LEFT OUTER JOIN RDB$COLLATIONS DCO ON ((DCO.RDB$COLLATION_ID = F.RDB$COLLATION_ID) AND (DCO.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID))
    WHERE (RF.RDB$RELATION_NAME = :TABLE_NAME) AND (COALESCE(RF.RDB$SYSTEM_FLAG, 0) = 0)
    ORDER BY RF.RDB$FIELD_POSITION;
    
    0 讨论(0)
提交回复
热议问题