SQLite模式信息元数据

68

我需要获取SQLite数据库中列名和它们所在的表。我需要一个包含两个列的结果集:table_name | column_name

在MySQL中,我可以通过查询数据库INFORMATION_SCHEMA来获取这些信息。然而,在SQLite中,可以使用表sqlite_master

sqlite> create table students (id INTEGER, name TEXT);
sqlite> select * from sqlite_master;
  table|students|students|2|CREATE TABLE students (id INTEGER, name TEXT)

我执行的查询是DDL构建查询(CREATE TABLE),对我不太有用,我需要解析它以获取相关信息。

我需要获取表列表并将其与列连接,或者只获取带有表名列的列。因此,PRAGMA table_info(TABLENAME) 对我不起作用,因为我没有表名。我想获取数据库中所有列的元数据。

有没有更好的方法通过查询数据库来获取这些信息作为结果集?

7个回答

105

你基本上在你的问题中已经命名了解决方案。

要获取表格(和视图)列表,请查询sqlite_master,就像这样:

SELECT name, sql FROM sqlite_master
WHERE type='table'
ORDER BY name;

(请参阅SQLite FAQ

要获取特定表中列的信息,请使用PRAGMA table_info(table-name);,如SQLite PRAGMA文档所述。

我不知道有没有办法通过单个查询返回tablename | columnname作为结果。 我不相信SQLite支持这一点。你最好的选择可能是将两种方法结合起来,以返回你正在寻找的信息 - 首先使用sqlite_master获取表列表,然后使用PRAGMA table_info()循环遍历它们以获取它们的列。


“pragma”不提供列数据。“.schema”可以提供,我已经将其结果粘贴在问题中了。我已经知道了这一点。我正在寻找一种方法。 - ahmet alp balkan
1
实际上,只要你有表名(可以从sqlite_master中获取),PRAGMA table_info()确实会返回列数据。我知道你正在寻找一个一步解决方案,只返回tablename|columname,而我建议的是一个可以在某种程序中使用的解决方法(两个步骤)。虽然我的答案并没有真正引入任何新信息,但我相信它可能会帮助某些人。据我所知,没有更好的方法...抱歉。但我不介意被证明是错误的 :-) - Tom Juergens
我的错。是的,pragma 命令可以做到那个,但如果我有100张表,首先我需要从 sqlite_master 获取表列表,然后我就需要执行100次 pragma 请求,这不是我想要的。 - ahmet alp balkan
1
是的,这就是它的意思,你需要使用sqlite_master和prama table_info的组合;这是正确的方法。 - user610650
1
这个答案提供了模式的转储,而不是请求的“tablename|columnName”。事实证明,“table_info”特权是可连接的,因此它是一个简单的选择:请参见https://dev59.com/M2w15IYBdhLWcg3wqNuM#53160348。 - mrm

28
SQLite的最新版本允许你现在可以选择针对PRAGMA结果查询,这使得操作变得轻松:
SELECT 
  m.name as table_name, 
  p.name as column_name
FROM 
  sqlite_master AS m
JOIN 
  pragma_table_info(m.name) AS p
WHERE
  m.type = 'table' 
ORDER BY 
  m.name, 
  p.cid

p.cid 保存了 CREATE TABLE 语句中的列顺序,从零开始索引。

David Garoutte 在 这里 给出了答案,但是这个 SQL 执行速度更快,并且列按照模式而不是按字母顺序排序。

请注意,table_info 还包含以下信息:

  • type(数据类型,如 integertext),
  • notnull(如果列有 NOT NULL 约束,则为 1
  • dflt_value(如果没有默认值,则为 NULL
  • pk(如果该列不是表的主键,则为 0;如果是第一个主键,则为 1;对于复合主键表,基于键序号的值为 2 或更大的值)

请参阅文档:https://www.sqlite.org/pragma.html#pragma_table_info


1
请注意,pk 是主键索引。对于主键只有一列的表,那么该列的 pk 值将为 1(如答案所述)。然而,如果主键有多个列,则 pk 值可以是 23 等等。 - AlainD
1
对于非表对象,这会导致很大的不幸(即引发错误)。添加 where m.type = 'table' 来修复。 - Keith Davies

12

有 ".tables" 和 ".schema [table_name]" 命令,可以给出与从 "select * from sqlite_master;" 得到的结果有点分开的版本。

还有 "pragma table_info([table_name]);" 命令,可以获得更好的解析结果,而不是一个构造查询:


sqlite> .tables
students
sqlite> .schema students
create table students(id INTEGER, name TEXT);
sqlite> pragma table_info(students);
0|id|INTEGER|0||0
1|name|TEXT|0||0

希望它能在一定程度上帮助到你...


但我认为.tables是一个特定于shell的函数,对吗?我需要从SQL界面执行它。 - ahmet alp balkan
是的,我想是这样的。无论如何,你需要实现一个解析器 :) - Mustafa Zengin

4
另一个有用的技巧是先从sqlite_master获取所有表名。然后对于每个表,发送一个查询"select * from t where 1 = 0"。如果分析所得到的查询结果结构 - 取决于你使用的语言/ api - 会得到描述列的丰富结构。在Python中:
c = ...db.cursor()
c.execute("select * from t where 1=0");
c.fetchall();
print c.description;

Juraj

PS. 我习惯使用“where 1=0”,因为记录限制语法似乎因数据库而异。此外,一个好的数据库将优化掉这个始终为假的子句。

在SQLite中,使用“limit 0”可以达到相同的效果。


2

2

如果您正在使用.Net,则可以使用DbConnection.GetSchema方法检索通常在INFORMATION_SCHEMA中的信息。如果您有一个抽象层,您可以为所有类型的数据库编写相同的代码(请注意MySQL似乎切换了限制数组的前两个参数)。


这是针对SQLite的吗?这是哪个.NET下的SQLite库?(即使不使用.NET也想知道) - ahmet alp balkan
2
SQLite不支持.GetSchema,会抛出一个不支持的异常。 - user117499
要使用 .NET 工具,您可能需要下载一个 NuGet 包。 - Iria

0

这是一个老问题,但由于它被查看的次数很多,我们正在为问题添加内容,因为大多数答案告诉您如何在SQLite数据库中查找TABLE名称。 当数据库中没有表名时,你该怎么办? 这正发生在我们的应用程序中,因为我们正在通过编程方式创建TABLES 因此,下面的代码将处理当TABLE不在或未被数据库创建时的问题。享受吧

    public void toPageTwo(View view){

    if(etQuizTable.getText().toString().equals("")){
        Toast.makeText(getApplicationContext(), "Enter Table Name\n\n"
                +"           OR"+"\n\nMake Table First", Toast.LENGTH_LONG 
   ).show();
        etQuizTable.requestFocus();
        return;
    }

    NEW_TABLE = etQuizTable.getText().toString().trim();
    db = dbHelper.getWritableDatabase();
    ArrayList<String> arrTblNames = new ArrayList<>();
    Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE 
   type='table'", null);

    if (c.moveToFirst()) {
        while ( !c.isAfterLast() ) {
            arrTblNames.add( c.getString( c.getColumnIndex("name")) );
            c.moveToNext();
        }
    }
    c.close();
    db.close();

    boolean matchFound = false;
    for(int i=0;i<arrTblNames.size();i++) {
        if(arrTblNames.get(i).equals(NEW_TABLE)) {
            Intent intent = new Intent(ManageTables.this, TableCreate.class 
   );
            startActivity( intent );
            matchFound = true;
        }
    }
    if (!matchFound) {
        Toast.makeText(getApplicationContext(), "No Such Table\n\n"
                +"           OR"+"\n\nMake Table First", Toast.LENGTH_LONG 
 ).show();
        etQuizTable.requestFocus();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接