【问题标题】:SQLite If Column ExistsSQLite 如果列存在
【发布时间】:2010-03-26 03:07:36
【问题描述】:

我想知道是否有一个很好的 IF NOT EXISTS 用于检查 SQLite 中的列和索引,还是我需要带回整个数据库架构并对此进行验证?

【问题讨论】:

    标签: database sqlite


    【解决方案1】:

    有一个名为sqlite_master 的系统目录表,您可以使用它来检查索引(或其他)名称:

    SELECT name FROM sqlite_master WHERE type='index' ORDER BY name;
    

    您可以使用pragma 来获取索引列:

    PRAGMA index_info(index-name);
    

    这个是用来获取表的列名的:

    PRAGMA table_info(table-name);
    

    【讨论】:

      【解决方案2】:

      是的,sqlite 支持以下语法:CREATE INDEX IF NOT EXISTS ...

      See here

      要检查列是否存在,您可以简单地尝试执行类似SELECT col from TABLE 的操作。如果它没有返回错误,则您的表包含 col

      【讨论】:

        【解决方案3】:

        在 SQLite 中,如果你想检查你的列/字段是否存在于你的表中......试试这个答案对我有用...... https://stackoverflow.com/a/28146506/3126569

        Cursor res = db.rawQuery("PRAGMA table_info("+tableName+")",null);
        int value = res.getColumnIndex(fieldName);
        

        【讨论】:

          【解决方案4】:

          我就是这么干的,

          INSERT  INTO AUDITEVENT (CODE, DESCRIPTION, AUDITEVENTPK)  
          SELECT 'value1', 'value2', 'value3' 
          WHERE NOT EXISTS (SELECT 1 FROM AUDITEVENT WHERE CODE = 'value1')
          

          在我的 IDConneciton 中,我有一个名为 ProcessCommandText 的方法,用于将查询从 SQL Server 语法更新为仅 SQLite。

          这是那个方法的实现

          public string ProcessSqlText(string text)
          {
              var result = text.Replace("SET ANSI_NULLS ON", "").
                      Replace("SET ANSI_NULLS ON", "").
                      Replace(" ASC)", ")").
                      Replace("TOP 100", "TOP(100)").
                      Replace("TOP 1", "TOP(1)").
                      Replace(" VARCHAR", " NVARCHAR").
                      Replace(" CHAR", " NCHAR").
                      Replace(" TEXT", " NTEXT").
                      Replace("WITH ( IGNORE_DUP_KEY = OFF)", "").
                      Replace("SET QUOTED_IDENTIFIER ON", "").
                      Replace("SET ANSI_PADDING ON", "").
                      Replace("SET ANSI_PADDING OFF", "").
                      Replace("SET ANSI_WARNINGS ON", "").Trim(' ').
                      Replace("WITH NOCHECK", "").
                      Replace("(nolock)", "").
                      Replace("CREATE CLUSTERED INDEX", "CREATE NONCLUSTERED INDEX").
                      Replace("CREATE UNIQUE CLUSTERED INDEX", "CREATE UNIQUE NONCLUSTERED INDEX").
                      Replace("[dbo].", "").
                      ToUpper().
                      Replace("NEWID()", "'" + Guid.NewGuid().ToString() + "'"). // NEWID() is not supported
                      Replace("GO", ""); // GO is not supported
          
          
              if (result.Contains("TOP(100)"))
              {
                  result = result.Replace("TOP(100)", "");
                  result += " LIMIT 100";
              }
              if (result.Contains("TOP(1)"))
              {
                  result = result.Replace("TOP(1)", "");
                  result += " LIMIT 1";
              }
              if (result.Contains("DATEPART"))
              {
                  result = result.Replace("DATEPART", "strftime");
                  result = result.Replace("minute", "'%M'");
                  result = result.Replace("day", "'%d'");
                  result = result.Replace("month", "'%m'");
                  result = result.Replace("year", "'%Y'");
              }
          
              result = TransformIfNotExistsQueriesToSqlLite(result);
              return result;
          }
          
          private string TransformIfNotExistsQueriesToSqlLite(string query)
          {
              var ifNotExistsRegEx = @"(IF NOT EXISTS\s+)\(+.+\)+\r+\n+INSERT+";
              var m = Regex.Match(query, @"(IF NOT EXISTS\s+)\(+.+\)+\r+\n+INSERT+", RegexOptions.IgnoreCase);
          
              if (m.Groups.Count > 0 && m.Groups[0].Value.Contains("IF NOT EXISTS"))
              {
                  var conditionalStatement = m.Groups[0].Value;
                  var newQuery = query.Replace(conditionalStatement, " INSERT ");
                  conditionalStatement = conditionalStatement.ToUpper().Replace("IF", "WHERE").Replace("INSERT", "");
          
                  newQuery = Regex.Replace(newQuery.ToUpper(), @"VALUES\s+\(+", " SELECT ");
                  var lastIndexOfClosingBracket = newQuery.LastIndexOf(')');
                  newQuery = newQuery.Substring(0, lastIndexOfClosingBracket);
                  return newQuery + " " + conditionalStatement;   
              }
              return query;
          }
          

          【讨论】:

            【解决方案5】:

            为什么不直接捕获异常?例如:

            try{
                db.execSQL("ALTER TABLE ACCOUNT_ENTRY ADD COLUMN ID_CONCEPT NUMBER(10)");
            }catch(Exception e){
                System.out.println(e);
            
            }
            

            【讨论】:

            • 这不好,因为如果它失败了,你只是在吞下异常。这个想法是只防止创建一个列两次,如果该列已经存在,它可能应该让你处于一个良好的状态。如果您的升级失败(由于某些其他原因),而您只是将其吞下,那么您将在其他地方崩溃,并且您将很难找到问题所在。
            • 捕获通用Exception 绝不是一个好主意。这只是为您的代码设置问题,并使您或将来需要在您调试后维护此代码的开发人员更难。
            猜你喜欢
            • 1970-01-01
            • 2013-11-23
            • 2011-02-06
            • 1970-01-01
            • 2011-04-05
            • 1970-01-01
            • 1970-01-01
            • 2015-03-31
            相关资源
            最近更新 更多