【问题标题】:How do I get a list of indexed Columns for a given Table如何获取给定表的索引列列表
【发布时间】:2012-11-16 23:39:30
【问题描述】:

给定一个 SQLite 数据库,我需要获取给定表中的哪些列被索引的列表,以及排序顺序。我需要从代码中执行此操作(C#,尽管这无关紧要),所以我真正需要的是一个 SQL 语句,如果存在的话,它会执行此操作。

我知道我可以做到:

SELECT sql FROM SQLite_master WHERE type = 'index' AND tbl_name = 'MyTableName'

然后手动解析生成的 SQL,但是否有一些我可以查询的元数据可以为我提供类似这些方面的信息?

---------------------------------- |姓名 |专栏 |方向 | ---------------------------------- | idx_a |科尔A |升学 | ---------------------------------- | idx_a_b | ColB, ColB |递减 | ----------------------------------

【问题讨论】:

    标签: c# sqlite


    【解决方案1】:

    使用PRAGMA index_list(table-name);PRAGMA index_info(index-name); extensions

    更新:PRAGMA schema.index_xinfo(index-name); 将返回键列的排序顺序。

    【讨论】:

    • 我看到我可以通过获取索引列表来预测列,然后获取用于派生列的信息,但是排序顺序呢?我没有看到任何说明它是 ASC 还是 DESC
    • @cacke 啊,是的,它似乎缺少排序顺序。叹息。
    【解决方案2】:

    在 where 子句中添加您想要的任何条件。字段是:

    CREATE TABLE sqlite_master (
      type TEXT,
      name TEXT,
      tbl_name TEXT,
      rootpage INTEGER,
      sql TEXT
    );
    

    Pastable select...索引要包含的重要字段是“sql”。不会列出创建表语句中定义的主键。

    select type, name, tbl_name, sql
    FROM sqlite_master
    WHERE type='index'
    

    【讨论】:

      【解决方案3】:

      这就是您的实际操作方式:所有索引元数据都可以通过“sqlite_master”表获得。请参阅 SQLite FAQ 的 Q7:http://www.sqlite.org/faq.html#q7

      【讨论】:

      • 我不确定为什么有人反对我,但让我重申一下:sqlite_master 表是通过 SQL 访问这些数据的本地方式。没有其他原生机制。
      • 但是 sqlite_master 表不保存索引名称、列和排序方向(在 SQL 语句之外)。我试图避免解析。
      【解决方案4】:

      @neil 简要提到了 SQLite Pragma statements PRAGMA INDEX_LIST['table_name']PRAGMA INDEX_INFO['index_name']。根据文档,这些既作为 SQLite 命令存在,也可以在函数中使用(即 pragma_index_list(table_name)pragma_index_info(index_name)

      为了更好地理解这一点,让我们看一下下面的 SQL:

      CREATE TABLE Assets
      (
          Asset_Id     INTEGER NOT NULL,
          Longitude    REAL    NOT NULL,
          Latitude     REAL    NOT NULL,
          Name         TEXT    NOT NULL,
          Installation REAL    NOT NULL,
          Constraint PK_Assets PRIMARY KEY (Asset_Id)
      );
      CREATE INDEX IX_Assets_Coordinate On Assets (Longitude, Latitude);
      CREATE INDEX IX_Assets_Name On Assets (Name);
      

      以下 SQLite 会话演示了如何查询索引:

      .mode csv
      sqlite> PRAGMA index_list('Assets');
      seq,name,unique
      0,IX_Assets_Name,0
      1,IX_Assets_Coordinate,0
      sqlite> PRAGMA index_info('IX_Assets_Name');
      seqno,cid,name
      0,3,Name
      sqlite> PRAGMA index_info('IX_Assets_Coordinate');
      seqno,cid,name
      0,1,Longitude
      1,2,Latitude
      sqlite>
      

      有趣的是PRAGMA 命令可以像SELECT 语句一样使用,所以在C# 中运行这些命令没有问题。

      SQLite Pragma statements 中,他们有一个有趣的示例 SQL 语句,用于枚举所有表的所有索引列:

      SELECT DISTINCT m.name || '.' || ii.name AS 'indexed-columns'
        FROM sqlite_master AS m,
             pragma_index_list(m.name) AS il,
             pragma_index_info(il.name) AS ii
       WHERE m.type = 'table'
       ORDER BY 1;
      

      【讨论】:

        【解决方案5】:
        SELECT 
            m.tbl_name as table_name,
            il.name as index_name,
            ii.name as column_name,
            CASE il.origin when 'pk' then 1 else 0 END as is_primary_key,
            CASE il.[unique] when 1 then 0 else 1 END as non_unique,
            il.[unique] as is_unique,
            il.partial,
            il.seq as sequence_in_index
        FROM sqlite_master AS m,
            pragma_index_list(m.name) AS il,
            pragma_index_info(il.name) AS ii
        WHERE 
            m.type = 'table'
            and m.tbl_name = 'YOUR TABLENAME HERE'
        GROUP BY
            m.tbl_name,
            il.name,
            ii.name,
            il.origin,
            il.partial,
            il.seq
        ORDER BY 1,6
        

        【讨论】:

          【解决方案6】:

          我找不到任何方法来简单地查询表元并获得我想要的 indo,所以如果有人需要它,这就是我使用的方法。是的,Regex 可能做得更干净,但你知道格言,如果 Regex 可以解决问题,那么现在你有两个问题。

          public class SqlIndexInfo
          {
              public string IndexName { get; set; }
              public string TableName { get; set; }
              public string[] Fields { get; set; }
              public bool IsAscending { get; set; }
          
              public bool IsComposite
              {
                  get { return Fields.Length > 1; }
              }
          }
          
          public static class Extensions
          {
              public static SqlIndexInfo ParseToIndexInfo(this string sql)
              {
                  sql = sql.Trim();
                  var info = new SqlIndexInfo();
          
                  var i = sql.IndexOf("CREATE INDEX", 0, StringComparison.InvariantCultureIgnoreCase);
                  if (i < 0) throw new ArgumentException("String is not valid CREATE INDEX SQL");
                  var indexNameStart = i + "CREATE INDEX".Length + 1;
          
                  i = sql.IndexOf(" ON ", 0, StringComparison.InvariantCultureIgnoreCase);
                  if (i < 0) throw new ArgumentException("String is not valid CREATE INDEX SQL");
                  var indexNameEnd = i;
                  var tableNameStart = i + " ON ".Length;
          
                  i = sql.IndexOf("(", 0, StringComparison.InvariantCultureIgnoreCase);
                  if (i < 0) throw new ArgumentException("String is not valid CREATE INDEX SQL");
                  var tableNameEnd = i;
                  var fieldNamesStart = i + 1;
          
                  i = sql.IndexOf(")", 0, StringComparison.InvariantCultureIgnoreCase);
                  if (i < 0) throw new ArgumentException("String is not valid CREATE INDEX SQL");
                  var fieldNamesEnd = i;
                  var directionStart = i + 1;
          
                  // TODO: strip brackets and/or single quotes?
          
                  info.IndexName = sql.Substring(indexNameStart, indexNameEnd - indexNameStart).Trim();
                  info.TableName = sql.Substring(tableNameStart, tableNameEnd - tableNameStart).Trim();
                  info.Fields = (from f in sql.Substring(fieldNamesStart, fieldNamesEnd - fieldNamesStart).Split(',')
                                where !string.IsNullOrEmpty(f)
                                select f.Trim()).ToArray();
          
                  if (directionStart >= sql.Length)
                  {
                      info.IsAscending = true;
                  }
                  else
                  {
                      info.IsAscending = sql.IndexOf("ASC", directionStart, StringComparison.InvariantCultureIgnoreCase) >= 0;
                  }
          
                  return info;
              }
          }
          

          【讨论】:

          • 多么痛苦!感谢分享。
          【解决方案7】:

          根据@Steve Lloyd 的回答进行优化,按ii.seqno 订购

          SELECT 
              m.tbl_name as table_name,
              il.name as index_name,
              ii.name as column_name,
              CASE il.origin when 'pk' then 1 else 0 END as is_primary_key,
              CASE il.[unique] when 1 then 0 else 1 END as non_unique,
              il.[unique] as is_unique,
              il.partial,
              il.seq as sequence_in_index,
              ii.seqno as sequence_in_column
          FROM sqlite_master AS m,
              pragma_index_list(m.name) AS il,
              pragma_index_info(il.name) AS ii
          WHERE 
              m.type = 'table'
              and m.tbl_name = 'YOUR TABLENAME HERE'
          GROUP BY
              m.tbl_name,
              il.name,
              ii.name,
              il.origin,
              il.partial,
              il.seq
          ORDER BY index_name,il.seq,ii.seqno
          

          【讨论】:

            猜你喜欢
            • 2021-05-05
            • 2014-04-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-06-23
            • 1970-01-01
            相关资源
            最近更新 更多