首页 > 解决方案 > 尝试插入时没有此类列的 SQLite 问题

问题描述

我使用 Sqlite 并且我有以下数据库,我正在为女性开发一个应用程序,它应该包含登录和注册。我在数据库中遇到了“没有这样的列”之类的问题

数据库

public class DB_MJG extends SQLiteOpenHelper {
public static final String name ="dataB.db";
public static final int version =1;

//Les atts de la table FEMME
public static final String table_Femme ="Femme";
public static final String ID_F =  "id";
public static final String NOM_F ="nom";
public static final String PRENOM_F="prenom";
public static final String PSEUDO="pseudo";
public static final String MDP="mdp";
public static final String GRP_F="grpSang";
public static final String AGE_F="age";
public static final String POIDS="poids";

public DB_MJG( Context context) {
    super(context, name, null, version);
}

@Override
public void onCreate(SQLiteDatabase db) {

    String CREATE_TABLE_FEMME = "CREATE TABLE " + table_Femme + "( 
"+ID_F+" INTEGER PRIMARY KEY AUTOINCREMENT, "
                                +NOM_F+" TEXT, "+PRENOM_F+" TEXT " + ")";


    db.execSQL(CREATE_TABLE_FEMME);
    System.out.println("table femme crée");

}

@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
    db.execSQL("DROP TABLE IF EXISTS "+table_Femme);
    db.execSQL("DROP TABLE IF EXISTS "+table_Enfant);

}

//insérer dans la table FEMME
public void insertFemme(Femme f)
{
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues vals = new ContentValues();


    vals.put(NOM_F,f.getNom());
    vals.put(PRENOM_F,f.getPrenom());
     db.insert(table_Femme,null,vals);
     db.close();
}


public ArrayList getFemme()
{
    ArrayList<Femme> femmes = new ArrayList<>();
    SQLiteDatabase db = this.getWritableDatabase();
     Cursor c = db.rawQuery("SELECT * FROM " +table_Femme, null);
    while(c.moveToNext()){
        Femme f = new Femme(c.getString(1),c.getString(2));
        femmes.add(f);
    }
    return femmes;
}

}

启动器活动

 public class MainActivity extends AppCompatActivity {
 DB_MJG db = new DB_MJG(this);
 SQLiteDatabase database ;
 String s = "";
 private Button log,sign;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    database = openOrCreateDatabase(db.name, Context.MODE_PRIVATE, null) ;

    db.insertFemme(new Femme("sara","sara"));
    ArrayList<Femme> femmes = db.getFemme();

    TextView textView= (TextView) findViewById(R.id.textView13);
    for(Femme f : femmes){
        String ch = "Nom :" +f.getNom() + " Prenom : " 
+f.getPrenom()+"\n";
        s = s +ch;
    }
    textView.setText(s);
}

错误

E/SQLiteLog: (1) table Femme has no column named nom
E/SQLiteDatabase: Error inserting nom=sara prenom=sara
android.database.sqlite.SQLiteException: table Femme has no column named             
 nom (code 1 SQLITE_ERROR): , while compiling: INSERT INTO     
Femme(nom,prenom) VALUES (?,?)
    at 
 android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native 
 Method)

当我编译时,它说没有这样的列。我已经定义了 nom 列。该数据库具有我试图用于插入的名称,但它不起作用。

标签: androidsqlite

解决方案


您遇到的主要问题是数据库助手的onCreate方法仅在创建数据库时调用,这是在它的生命周期中调用一次。

因此,如果通过修改创建表 SQL 对结构(模式)进行了任何更改,如 onCreate 方法中使用的那样除非删除数据库或以其他方式调用onCreate方法,否则它们将不会被反映。

通常,至少在开发应用程序时,通过首先执行以下操作之一来应用此类更改:-

  1. 删除 App 的数据(这会删除数据库,因此会自动调用onCreate)。
  2. 卸载应用程序(并因此删除应用程序的数据)。
  3. 如果编写onUpgrade方法以删除更改的表并重新创建表(通常/通常通过调用onCreate方法)

执行上述任一操作后,重新运行应用程序将导致应用结构更改。

  • 请注意,上述内容将导致现有数据丢失,不适用于已部署的应用程序。

在您的情况下,如果使用选项 3,onUpgrade方法需要在删除表后包括创建表,因为它只删除表。

您在 MainActivity 中的代码也过于复杂,因为它利用打开数据库而不使用 SQLite OpenHelper打开数据库,而是使用 SQLiteDatabase openOrCreate方法打开它(这不会导致 SQLiteOpenHelper(DB_MJG 是 SQLiteOpenHelper 的子类) ) onCreate方法被调用)。但是,由于怪癖/运气,当您开始使用 DB_MJG 的实例时,即db,因为该实例是在 openOrCreate 方法之前创建的,它实际上会继续调用onCreat方法。

但是,使用一种方法打开数据库会简单得多。

因此,我建议只使用DB_MJG DatabseHelper 来实现。

使固定

基本的解决方法是引入更改后的结构。因此,应采取上​​述 3 项中的一项。

如果使用 3. 则需要修改onUpgrade方法以调用onCreate方法,然后增加版本号。那就是 onUpgrade 方法可以是:-

@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
    db.execSQL("DROP TABLE IF EXISTS "+table_Femme);
    db.execSQL("DROP TABLE IF EXISTS "+table_Enfant);
    onCreate(db); //<<<<<<<<<< ADDED so that onUpgrade creates the tables after they have been dropped
}

附加/推荐

关闭光标

在 DB_MJG.java 中,getFemme 方法使光标保持打开状态。这可能会导致打开的数据库或游标过多,因此建议该行:-

c.close();

被添加到getFemme方法中,所以它变成:-

public ArrayList getFemme()
{
    ArrayList<Femme> femmes = new ArrayList<>();
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor c = db.rawQuery("SELECT * FROM " +table_Femme, null);
    while(c.moveToNext()){
        femmes.add(new Femme(c.getString(c.getColumnIndex(NOM_F)),c.getString(c.getColumnIndex(PRENOM_F))));
    }
    c.close(); //<<<<<<<<<< should always close a cursor when finished with it
    return femmes;
}
  • 请注意,上面还消除了对中间 Femme 对象f的需要。

使用 DB_MJG 打开数据库

使用 SQliteOpenHelper 的子类时无需打开或创建数据库,因为它会执行此操作。所以MainActivity.java可能是:-

public class MainActivity extends AppCompatActivity {

    DB_MJG db; // Only declare the DB_MJG object.
    private Button log,sign;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        db = new DB_MJG(this);
        db.insertFemme(new Femme("sara","sara"));
        ArrayList<Femme> femmes = db.getFemme();
        TextView textView= (TextView) findViewById(R.id.textView13);
        StringBuilder sb = new StringBuilder(); //<<<<<<<<<< ADDED - Use StringBuilder in a loop
        for(Femme f : femmes){
            sb.append("Nom: ").append(f.getNom()).append(" Prenom: ").append(f.getPrenom());
        }
        textView.setText(sb.toString());
    }
}

推荐阅读