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.
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
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;
});
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
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 SQL
CREATE TABLE &c &c
qui décrit la table (mais vous devrez analyser cela, donc je pense que PRAGMA table_info
est plus ... pragmatique ;-).
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);