Подтвердить что ты не робот

Как я могу получить описание таблицы (поля и типы) из Firebird с помощью dbExpress

Я написал инструмент для отображения структур баз данных, используя методы GetTableNames и GetFieldNames для TSQLConnection. Как я могу получить типы каждого имени поля, похожие на следующий список (который является частью DDL, необходимой для построения таблицы)?

TABLE: ARTICLES
ID INTEGER NOT NULL
PRINTED SMALLINT DEFAULT 0
ACADEMIC SMALLINT
RELEVANCE SMALLINT
SOURCE VARCHAR(64) CHARACTER SET WIN1251 COLLATE WIN1251
NAME VARCHAR(128) CHARACTER SET WIN1251 COLLATE WIN1251
FILENAME VARCHAR(128) CHARACTER SET WIN1251 COLLATE WIN1251
NOTES VARCHAR(2048) CHARACTER SET WIN1251 COLLATE WIN1251
4b9b3361

Ответ 1

Это неполное (потому что я никогда не использовал типы данных массива Firebird) и не сильно тестировался, но, возможно, это даст вам хорошую отправную точку:

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;

Ответ 2

Использовать прямой доступ к таблицам RDB $. Например:

SELECT * FROM rdb$relations

предоставит вам список всех таблиц в базе данных.

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

приведет к списку всех полей данной таблицы с информацией типа поля. Параметр RN - это имя таблицы.

Используя информацию из таблиц RDB $, можно легко построить DDL выражение. Следующий запрос подскажет вам, как это сделать:

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>'

Ответ 3

Используя ссылку, предоставленную TLama, я нашел свое собственное решение, которое несколько похоже на вышеупомянутые решения, но проще.

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 - это имя таблицы, которое передается в качестве параметра для запроса.

В контексте у меня есть дерево, которое имеет в качестве своих узлов имена таблиц для данной базы данных; для каждого node дочерние узлы представляют собой поля вместе с их определениями.

 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;

Вот скриншот программы в действии. Я понимаю, что формат не совпадает с DDL, который я цитировал, но очевидно, что каждое поле означает (по крайней мере, для меня, и это программа для моего личного использования).

enter image description here

Ответ 4

Я сделал litle изменение первого варианта поддержки, вычисленного по полям, добавив field_position и сделал вид, чтобы сделать его более легким.

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
;