web-dev-qa-db-fra.com

Rechercher des noms de colonnes SQLite dans une table vide

Pour le plaisir, j'écris un outil de "documentation de schéma" qui génère une description des tables et des relations dans une base de données. Je suis en train de le faire fonctionner avec SQLite.

J'ai réussi à extraire les noms de toutes les tables d'une base de données SQLite via une requête sur la table sqlite_master. Pour chaque nom de table, je déclenche ensuite un simple

select * from <table name>

requête, puis utilisez les API sqlite3_column_count() et sqlite3_column_name() pour collecter les noms de colonne, que je nourris ensuite à sqlite3_table_column_metadata() pour obtenir des informations supplémentaires. Assez simple, non?

Le problème est que cela ne fonctionne que pour les tables qui ne sont pas vides. Autrement dit, les API sqlite_column_*() ne sont valides que si sqlite_step() a renvoyé SQLITE_ROW, ce qui n'est pas le cas pour les tables vides.

La question est donc, comment puis-je découvrir les noms de colonne pour les tables vides? Ou plus généralement, existe-t-il un meilleur moyen d'obtenir ce type d'informations de schéma dans SQLite?

Je me sens comme il doit y avoir une autre table sqlite_xxx cachée cachée quelque part contenant cette information, mais jusqu’à présent je n’ai pas pu la trouver. 

36
Drew Hall
sqlite> .header on
sqlite> .mode column
sqlite> create table ABC(A TEXT, B VARCHAR);
sqlite> pragma table_info(ABC);
cid         name        type        notnull     dflt_value  pk
----------  ----------  ----------  ----------  ----------  ----------
0           A           TEXT        0                       0
1           B           VARCHAR     0                       0
62
pragmanatu

Exécutez la requête:

PRAGMA table_info( your_table_name );

Documentation

10
Nick Dandoulakis

PRAGMA table_info( your_table_name ); ne fonctionne pas dans HTML5 SQLite.

Voici un petit extrait de code JavaScript SQLite HTML5 qui obtient les noms de colonne de votre_nom_table même s'il est vide. J'espère que c'est utile.

tx.executeSql('SELECT name, sql FROM sqlite_master WHERE type="table" AND name = "your_table_name";', [], function (tx, results) {
  var columnParts = results.rows.item(0).sql.replace(/^[^\(]+\(([^\)]+)\)/g, '$1').split(',');
  var columnNames = [];
  for(i in columnParts) {
    if(typeof columnParts[i] === 'string')
      columnNames.Push(columnParts[i].split(" ")[0]);
  }
  console.log(columnNames);
  ///// Your code which uses the columnNames;
});
4
GeekTantra

Exécuter cette requête 

select * from (select "") left join my_table_to_test b on -1 = b.rowid;

Vous pouvez l'essayer sur Moteur sqlite en ligne

4
user941581

L'instruction PRAGMA suggérée par @pragmanatu fonctionne également dans toutes les interfaces de programmation. Sinon, la colonne sql de sqlite_master contient l'instruction SQLCREATE TABLE &c &c qui décrit la table (mais vous devrez analyser cela, donc je pense que PRAGMA table_info est plus ... pragmatique ;-).

3
Alex Martelli

Si vous poursuivez SQLite 3.8.3 ou une version ultérieure (prend en charge la clause WITH), cette requête récursive devrait fonctionner pour les tables de base. Sur CTAS, YMMV.

WITH
    Recordify(tbl_name, Ordinal, Clause, Sql)
AS
    (
     SELECT
        tbl_name,
        0,

        '',
        Sql
     FROM
        (
         SELECT
            tbl_name,
            substr
            (
             Sql,
             instr(Sql, '(') + 1,
             length(Sql) - instr(Sql, '(') - 1
            ) || ',' Sql
         FROM
            sqlite_master
         WHERE
            type = 'table'
        )
     UNION ALL
     SELECT
        tbl_name,
        Ordinal + 1,
        trim(substr(Sql, 1, instr(Sql, ',') - 1)),
        substr(Sql, instr(Sql, ',') + 1)
     FROM
        Recordify
     WHERE
        Sql > ''
       AND  lower(trim(Sql)) NOT LIKE 'check%'
       AND  lower(trim(Sql)) NOT LIKE 'unique%'
       AND  lower(trim(Sql)) NOT LIKE 'primary%'
       AND  lower(trim(Sql)) NOT LIKE 'foreign%'
       AND  lower(trim(Sql)) NOT LIKE 'constraint%'
    ),
    -- Added to make querying a subset easier.
    Listing(tbl_name, Ordinal, Name, Constraints)
AS
    (
     SELECT
        tbl_name,
        Ordinal,
        substr(Clause, 1, instr(Clause, ' ') - 1),
        trim(substr(Clause, instr(Clause, ' ') + 1))
     FROM
        Recordify
     WHERE
        Ordinal > 0
    )
SELECT
    tbl_name,
    Ordinal,
    Name,
    Constraints
FROM
    Listing
ORDER BY
    tbl_name,
    lower(Name);
0
user2812175