안녕하세요, 츄르 사려고 코딩하는 집사 코집사입니다.
이번 포스팅 주제는 안드로이드 스튜디오에서 SQLite를 이용한 DB 추가, 삭제, 조회 등을 가진 것을 만들다가 생긴 에러를 잡아서 문제 해결로 올리려고 합니다. 진짜 이 문제 때문에, 2일 정도 넘게 시간을 잡아먹었네요...ㅠ
제가 하려고 했던 것은, 라디오 버튼(Radio button)에서 값을 받아와 DB에 저장하려고 했습니다.
그래서, 열심히 작업을 했었죠.
라디오 그룹에서 체크된 라디오 버튼을 찾아서 그 ID를 변수에 저장을 하고, 그 변수를 DB에 저장하려고 하는 순간 아래와 같은 오류를 Logcat에서 찾았습니다.
DB 구성은 다음과 같이 했었습니다.
"CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, memo TEXT, priority INTEGER);");
근데, _id는 컬럼으로 들어가지 않더라구요. id는 자동적으로 DB에 데이터가 들어오면 증가하게 되었습니다.
그래서, 데이터를 넣을 때 다음과 같이 sql를 짰습니다.
sql = String.format("INSERT INTO person VALUES(NULL, '"+name+"','"+memo+"',"+check+");");
그랬더니 아래와 같은 문제가 발생했습니다. App을 실행하니 App이 자꾸 종료가 됐습니다.
Caused by: android.database.sqlite.SQLiteException: table person has 3 columns but 4 values were supplied (code 1): , while compiling: INSERT INTO person VALUES(NULL,'Name','Name','1');
person이라는 table에 3개의 컬럼을 가지고 있는데 4개의 변수 값을 넣었다고 에러가 뜬겁니다.
그래서, 아 NULL을 넣어서 그런거구나... 생각을 하고 NULL을 지웠습니다.
sql = String.format("INSERT INTO person VALUES('"+name+"','"+memo+"',"+check+");");
그랬더니, 이제는 아래와 같은 에러가 발생했습니다.
Error Code : 20 (SQLITE_MISMATCH)
Caused By : Data type mismatch.
(datatype mismatch (code 20))
데이터 타입이 맞지 않다고.... 오류가 떴습니다. 근데 아무리 생각을 해도 데이터 타입도 다 맞추고 했는데 뭔가 이상하더라구요. priority 라는 변수를 지우고 name과 memo만 이루어진 컬럼에 _id 로 테이블로 구성을 시켜서 했습니다. 근데 잘 넣어지는 겁니다.
App에서 작동을 추가를 해보고 지우고 조회를 해봤습니다.
지울 땐 DELETE FROM person으로 person 테이블에 있는 모든 row를 다 지웠는데 _id는 그대로 남아있더라구요
즉, 아래와 같이 테이블이 구성됐습니다.
_id name memo
1
2
3
4
5
6
_id는 지워지지 않고, name과 memo column만 지워져서 뭔가 많은 생각이 떠오르더라구요.
저 _id가 문제가 있겠다.. 라고 생각을 해서 오픈 채팅방에 물어도 보고, 현직자에게도 물어 봤는데도 이런 상황을 처음 겪어봤다라고 하더라구요. 진짜 2일동안 삽질을 한 결과 결국엔 해결을 했습니다!
해결 방법으로는 너무 간단해서 성취감보단 허탈함이 더 컸습니다.
해결 방법 : _id를 가진 table을 지우고 새로운 table을 만들었더니 해결....
왜 이 생각을 못했는지 모르겠네요....
뭐가 안된다고 하면 컴퓨터를 껐다가 키면 다 됐었는데 똑같은 방법으로 했으면 됐을텐데.. 계속 이 생각만 했습니다.
이것과 관련된 문제가 구글이나 다음, 네이버에는 찾아봐도 없어서 눈물날 뻔 했지만, 그래도 해결을 할 수 있어서 좋았고, 다른 공부하는 분들도 저와 같은 문제가 발생하면 이 글을 보고 꼭 해결했으면 좋겠습니다.
마지막으로, 완료된 화면과 코드를 올려드리겠습니다.
-2019년 1월 18일 금요일 내용 추가합니다.-
버전 업을 해서 DB에 컬럼들을 수정하면 해결할 수도 있을 것 같습니다.
<MainActivity.java>
package com.example.myyou.ttt;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText nameEdit;
EditText memoEdit;
TextView result;
DBHelper dbHelper;
final static String dbName = "yg.db";
final static int dbVersion = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nameEdit = (EditText)findViewById(R.id.nameedit);
memoEdit = (EditText)findViewById(R.id.memoedit);
result = (TextView)findViewById(R.id.result);
dbHelper = new DBHelper(this, dbName, null, dbVersion);
}
public void mOnClick(View v){
SQLiteDatabase db;
String sql;
switch (v.getId()) {
case R.id.insert: //추가 버튼(insert)
RadioGroup rg = (RadioGroup)findViewById(R.id.radiogroup);
String name = nameEdit.getText().toString();
String memo = memoEdit.getText().toString();
int check = rg.getCheckedRadioButtonId();
RadioButton rd = (RadioButton)findViewById(rg.getCheckedRadioButtonId());
//String radiovalue = check.getText().toString();
//String radiovalue = ((RadioButton)findViewById(rg.getCheckedRadioButtonId())).getText().toString();
//int id = rg.getCheckedRadioButtonId();
//RadioButton rb = (RadioButton)findViewById(id);
//Toast.makeText(MainActivity.this,rb.getText(),Toast.LENGTH_SHORT).show();
db = dbHelper.getWritableDatabase();
sql = String.format("INSERT INTO yg VALUES('"+name+"','"+memo+"',"+check+");");
db.execSQL(sql);
result.append("\nInsert Success");
break;
case R.id.delete: //전체삭제 버튼(delete)
db = dbHelper.getWritableDatabase();
sql = "DELETE FROM yg;";
db.execSQL(sql);
result.append("\nDelete Success");
break;
case R.id.select: //조회 버튼(select)
db = dbHelper.getReadableDatabase();
sql = "SELECT * FROM yg;";
Cursor cursor = db.rawQuery(sql, null);
if(cursor.getCount() > 0){
while(cursor.moveToNext()){
result.append(String.format("\n이름 = %s, 메모 = %s, 우선순위 = %s",
cursor.getString(0),cursor.getString(1),cursor.getString(2)));
}
}else{
result.append("\n조회결과가 없습니다.");
}
cursor.close();
break;
}
dbHelper.close();
}
class DBHelper extends SQLiteOpenHelper {
//생성자 - database 파일을 생성한다.
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
//DB 처음 만들때 호출. - 테이블 생성 등의 초기 처리.
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE yg (name TEXT, memo TEXT, priority INTEGER);");
result.append("\nyg 테이블 생성 완료.");
}
//DB 업그레이드 필요 시 호출. (version값에 따라 반응)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS yg");
onCreate(db);
}
}
}
이상으로, 츄르 사려고 코딩하는 집사! 코집사였습니다.
'App > 안드로이드 스튜디오' 카테고리의 다른 글
[안드로이드 스튜디오(Android Studio)] Windows 10에 안드로이드 스튜디오(Android Studio) 설치하기 (0) | 2019.05.15 |
---|---|
안드로이드 스튜디오 - 패키지 이름 바꾸는 방법('com.example'이(가) 제한된 상태이므로 다른 패키지 이름을 사용해야 합니다.) (5) | 2019.01.31 |
안드로이드 스튜디오 리사이클러 뷰(Recycler View) 사용법(1) (0) | 2019.01.29 |
안드로이드 스튜디오(Android Studio) SQLite를 이용한 데이터베이스(DB) 만들기 (11) | 2019.01.22 |
안드로이드 스튜디오 앱(App) 내부에 있는 SQLite 데이터베이스 테이블 보는 방법 (1) | 2019.01.21 |
안드로이드 스튜디오(Android Studio) Cursor와 데이터베이스(DB) (0) | 2019.01.17 |
안드로이드 스튜디오(Android Studio) findViewById (3) | 2019.01.16 |
안드로이드 스튜디오 setContentView() (1) | 2019.01.16 |
최근댓글