안드로이드 데이터베이스(DB) 프로그래밍 2. [SQLiteDatabase] (Android Database 2)

2017. 4. 10. 17:35


1. 관계형 데이터베이스(Relational Database)

지난 글 [안드로이드 데이터베이스(DB) 다루기 1 - 관계형 데이터베이스]에서 관계형 데이터베이스(Relational Database)의 기본 개념과 용어, 그리고 데이터베이스를 다루기 위해 필수적으로 알아야 하는 SQL(Structured Query Language) 등에 대해 살펴보았습니다. 안드로이드에서 데이터베이스를 사용하는 구체적인 방법을 설명하기에 앞서, 데이터베이스 프로그래밍을 하기 위해서 미리 알아두면 좋을, 아니, 최소한 한번쯤은 살펴봐야 할 기초적인 데이터베이스 이론에 대해 설명하였죠.


안드로이드에서 기본적으로 제공되는 데이터베이스인 SQLite가 관계형 데이터베이스 구조를 따르고, 또한 표준으로 정의된 SQL 기능의 대부분을 지원하기 때문에, 안드로이드에서 SQLite를 사용하기 위해 데이터베이스 이론을 공부한다는 것은 상당한 도움이 되는 과정이라 할 수 있습니다. 만약, 데이터베이스를 처음 접하거나, 그 개념 또는 용어가 머리 속에 정리되어 있지 않다면, [안드로이드 데이터베이스(DB) 다루기 1 - 관계형 데이터베이스]에서 정리한 내용을 읽은 다음, 이 글의 내용을 살펴보시길 권해드립니다.


자, 이제 관계형 데이터베이스에 대한 내용에 이은 두 번째 주제로 넘어가서, 안드로이드에서 제공되는 SQLite 관련 클래스에 대한 구조 및 API 함수들의 사용법에 대해 설명할 차례가 되었습니다. 대부분의 내용이 데이터베이스 처리를 위한 SQL 문과 그 SQL을 실행하는 함수에 대한 설명, 그리고 함수의 실행 결과를 확인하는 방법들로 구성될텐데요, 여기서 설명하는 내용 정도만 이해하고 있어도 실질적인 구현 과정에서 큰 어려움없이 SQLite 를 사용할 수 있을거라 생각합니다.


그럼 지금부터 SQLite를 다루는 클래스에 대한 구조와 API 함수들의 사용법에 대해 설명하도록 하겠습니다.

2. 안드로이드에서 SQLite 사용하기.

앞서 설명했듯이 안드로이드에서 기본적으로 제공되는 데이터베이스는 SQLite입니다. SQLite는 비교적 작은 규모의 안드로이드 앱에서 사용하기 적합한 데이터베이스로써, SQLite에서 제공하는 몇 가지 API 함수를 호출하는 것만으로 데이터베이스 기능을 사용할 수 있는 특징이 있습니다.


안드로이드의 SQLite 관련 클래스 및 API 함수는 "android.database.sqlite" 패키지에 들어 있으며, 그 중 가장 중요한 클래스는 SQLiteDatabase 클래스입니다.


아래 그림은 앞으로 설명할 SQLite 데이터베이스를 사용하는 과정을 요약한 것입니다.

SQLiteDatabase 사용하기


2.1 SQLiteDatabase 클래스

SQLite 데이터베이스에 데이터를 추가(INSERT)하거나, 삭제(DELETE), 수정(UPDATE) 또는 조회(SELECT)를 하기 위해서는 SQLiteDatabase 클래스를 사용해야 합니다. 그리고 데이터가 저장될 테이블 생성 및 삭제, 수정 등의 기능 또한 SQLiteDatabase 클래스에서 제공되죠. (https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html)


즉, SQLiteDatabase 클래스는 하나의 SQLite 데이터베이스를 다루기 위한 핵심 역할을 수행하는 클래스입니다. 그러므로 SQLite 데이터베이스 작업을 수행하기 전 반드시 SQLiteDatabase 클래스 객체의 참조를 획득해야 합니다.

SQLiteDatabase 클래스


일단 객체에 대한 참조를 획득하고 나면, SQLiteDatabase 클래스에 정의된 함수를 통해 데이터베이스 기능을 사용할 수 있습니다.


SQLiteDatabase 객체의 참조를 획득하는 것은 SQLite 데이터베이스 파일을 열거나, 새로운 파일을 생성함으로써 획득할 수 있습니다.

2.2 SQLite 데이터베이스 열기. (SQLiteDatabase 객체 참조 획득)

SQLite 데이터베이스를 사용하기 위해서는 가장 먼저 데이터베이스 파일을 열거나 생성해야 합니다. 이는 SQLiteDatabase 클래스에 정의된 몇 가지 static 함수를 통해 수행될 수 있습니다.

리턴 타입 메소드 이름
SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags)
SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler)
SQLiteDatabase openOrCreateDatabase(File file, SQLiteDatabase.CursorFactory factory)
SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler)
SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory)

표에 나와 있는 static 함수의 이름을 통해 알 수 있듯이, 데이터베이스를 여는 과정에서 만날 수 있는 상황은 크게 두 가지로 나뉠 수 있습니다. 이미 데이터베이스 파일이 존재하는 경우(openDatabase() 함수 사용)와 데이터베이스 파일이 없을 수도 있는 경우(openOrCreateDatabase() 함수 사용)가 바로 그것인데요. 주로 openOrCreateDatabase() 함수를 사용하여, 데이터베이스 파일 열기를 시도한 다음 만약 파일이 존재하지 않는다면 새로운 데이터베이스 파일을 생성하는 방법을 사용합니다.


아래의 코드는 openOrCreateDatabase() 함수를 사용하여 "sample.db" 파일을 여는 예제입니다. 이 때 만약 "sample.db" 파일이 존재하지 않는다면, 새로 만들게 됩니다.

[STEP-1] SQLiteDatabase - 데이터베이스 열기. (openOrCreateDatabase() 함수 호출.)
    SQLiteDatabase sqliteDB = null ;

    try {
        sqliteDB = SQLiteDatabase.openOrCreateDatabase("sample.db", null) ;
    } catch (SQLiteException e) {
        e.printStackTrace() ;
    }

2.3 SQLite 데이터베이스에 테이블 생성하기. (CREATE TABLE)

SQLite 데이터베이스 파일을 열어 SQLiteDatabase 객체의 참조를 확보했다면, 이제 객체의 참조를 통해 데이터베이스에 데이터를 추가하거나, 삭제 또는 조회 등의 작업을 수행할 수 있습니다. 하지만 데이터베이스 파일을 열었다고 해서 무턱대고 데이터를 추가할 순 없죠. 앞서 관계형 데이터베이스에 대해 설명할 때, 데이터베이스에 데이터를 저장하기 위해 데이터를 구조화하는 과정에 대해 간단히 언급하였습니다. 이 때 데이터 구조화의 결과로써, 데이터의 속성과 그 값의 관계를 나타내는 테이블(Table)이 만들어지는 것을 설명했습니다.


즉, SQLite 데이터베이스 파일을 열었다면, 다음 해야 할 일은 데이터베이스 내에 테이블(Table)을 생성하는 것입니다. SQLite 데이터베이스에 테이블을 만드는 방법은 테이블 생성을 위한 SQL 문자열을 SQLiteDatabase 클래스의 execSQL() 함수를 통해 전달하는 것입니다.


아래 예제 코드는 정수형(INTEGER) 데이터를 저장하기 위한 "NO" 필드와 문자열(TEXT) 데이터를 저장하기 위한 "NAME" 필드를 가지는 "ORDER_T"라는 테이블을 생성하는 코드입니다.

[STEP-2] SQLiteDatabase - 테이블 만들기. ("CREATE TABLE ... " 문을 execSQL()로 실행.)
    String sqlCreateTbl = "CREATE TABLE ORDER_T (NO INTEGER, NAME TEXT)" ;

    sqliteDB.execSQL(sqlCreateTbl) ;

그런데 "CREATE TABLE" SQL 문은 데이터베이스 파일이 생성되고나서 최초에 한번만 실행할 수 있습니다. 만약 생성하고자 하는 테이블과 같은 이름의 테이블이 이미 존재하는 상황에서 "CREATE TABLE" 명령을 실행하면, 다음과 같이 예외 상황이 발생합니다.

Caused by: android.database.sqlite.SQLiteException: table ORDER_T already exists (code 1): , while compiling: CREATE TABLE ORDER_T (NO INTEGER, NAME TEXT)

이런 경우, 테이블 중복 생성으로 인한 예외 상황(Exception)이 발생하는 것을 막기 위해서는 테이블이 존재하지 않는 경우에만 테이블을 새로 만들도록 만들어야 합니다. 이를 위해서는 "CREATE TABLE" 문에 "IF NOT EXISTS" 옵션을 추가하여 실행하면 됩니다. 예외 상황이 발생하는 문제를 해결한 코드는 아래와 같습니다.

[STEP-2.1] SQLiteDatabase - 테이블이 없는 경우 새로 만들기. ("CREATE TABLE IF NOT EXISTS ... " 문을 execSQL()로 실행.)
    String sqlCreateTbl = "CREATE TABLE IF NOT EXISTS ORDER_T (NO INTEGER, NAME TEXT)" ;

    sqliteDB.execSQL(sqlCreateTbl) ;

2.4 테이블에 데이터 추가, 수정, 삭제하기.

2.4.1 테이블에 데이터 추가하기. (INSERT)

SQLite 데이터베이스를 열고 테이블을 생성했다면, 이제 생성된 테이블에 데이터를 추가할 수 있습니다. 테이블에 데이터를 추가할 때는 "INSERT" 문을 사용합니다.


아래 예제 코드는 앞서 만든 "ORDER_T" 테이블의 "NO", "NAME" 필드에 각각 1과 "ppotta" 값을 추가하는 코드입니다. 앞서 테이블 생성 때와 마찬가지로 SQLiteDatabase 클래스의 execSQL() 함수를 사용합니다.

[STEP-3] SQLiteDatabase - 데이터 추가. ("INSERT INTO ... " 문을 execSQL()로 실행.)
    String sqlInsert = "INSERT INTO ORDER_T (NO, NAME) VALUES (1, 'ppotta')" ;

    sqliteDB.execSQL(sqlInsert) ;

"INSERT" 문을 실행하면 테이블에 새로운 데이터를 추가합니다. 이 때 새로 추가되는 값은 테이블 내 동일한 값을 가진 로우(Row)의 존재 여부와 관계없이, 새로운 로우(Row)로 추가됩니다.


그런데 어떤 상황에서는 새로운 값이 추가되는 것 대신, 기존에 저장된 로우(Row)의 값을 수정하고 싶을 때도 있을 것입니다. 물론 뒤에서 살펴볼 "UPDATE" 명령을 통해 데이터를 수정하는 것이 일반적이긴 하지만, "INSERT" 명령을 실행할 때 미리 조건에 맞는 데이터가 있으면, 새로운 로우(Row)를 추가하지 않고 이미 들어있던 로우(Row)의 값을 수정하도록 만들 수 있습니다. 이를 위해 "INSERT OR REPLACE" 문을 사용합니다.

[STEP-3.1] SQLiteDatabase - 데이터 추가. 이미 존재하면 수정. ("INSERT OR REPLACE INTO ... " 문을 execSQL()로 실행.)
    String sqlInsert = "INSERT OR REPLACE INTO ORDER_T (NO, NAME) VALUES (1, 'ppotta')" ;

    sqliteDB.execSQL(sqlInsert) ;
2.4.2 테이블 데이터 수정하기. (UPDATE)

테이블에 데이터가 추가되어 있다면, "UPDATE" 문을 사용하여 데이터의 내용을 수정할 수 있습니다.


아래 예제 코드는 ORDER_T 테이블의 "NO"와 "NAME" 필드 값을 각각 2, "ppotta2"로 수정하는 코드입니다.

[STEP-4] SQLiteDatabase - 데이터 수정. ("UPDATE ... " 문을 execSQL()로 실행.)
    String sqlUpdate = "UPDATE ORDER_T SET NO=2, NAME='ppotta2'" ;

    sqliteDB.execSQL(sqlUpdate) ;

그런데 위의 코드를 수행하면 테이블 내의 모든 행의 값이 수정됩니다. 이는 "UPDATE" 문이 실행될 데이터에 대한 조건이 지정되지 않았기 때문입니다. 만약 모든 로우(Row)가 아닌 특정 로우(Row)의 값만 수정하고자 한다면, 아래와 같이 "UPDATE" 문에 "WHERE"를 사용하여 조건을 추가하면 됩니다.


아래는 "WHERE"를 사용하여 "NO" 필드 값이 1인 로우(Row)에 대해서만 값을 수정하도록 만드는 코드입니다.

[STEP-4.1] SQLiteDatabase - 조건에 해당하는 데이터 수정. ("UPDATE ... WHERE ... " 문을 execSQL()로 실행.)
    String sqlUpdate = "UPDATE ORDER_T SET NO=2, NAME='ppotta2' WHERE NO=1" ;

    sqliteDB.execSQL(sqlUpdate) ;
2.4.3 테이블 데이터 삭제하기. (DELETE)

테이블에 저장되어 있는 데이터를 삭제하려면 "DELETE" 문을 사용합니다.


아래 예제 코드는 "ORDER_T" 테이블의 모든 데이터를 삭제하는 코드입니다.

[STEP-5] SQLiteDatabase - 데이터 삭제. ("DELETE ... " 문을 execSQL()로 실행.)
    String sqlDelete = "DELETE FROM ORDER_T" ;

    sqliteDB.execSQL(sqlDelete) ;

만약 "ORDER_T" 테이블의 데이터 중에서 특정 로우(Row)만 삭제하길 원한다면 "WHERE"를 추가하여 조건을 지정할 수 있습니다.


아래 코드는 "NO"의 값이 2인 모든 데이터를 삭제하는 예제입니다.

[STEP-5.1] SQLiteDatabase - 조건에 맞는 데이터 삭제. ("DELETE ... WHERE ... " 문을 execSQL()로 실행.)
    String sqlDelete = "DELETE FROM ORDER_T WHERE NO=2" ;

    sqliteDB.execSQL(sqlDelete) ;


2.5 테이블 데이터 조회하기.

테이블에 저장된 데이터를 조회하려면 "SELECT" 문을 사용합니다. 하지만 앞에서 살펴 본 데이터 추가, 수정, 삭제를 위한 SQL 문장을 실행할 때와는 다르게 추가적으로 알아두어야 할 요소가 두 가지 있습니다. 바로 쿼리(Query)와 커서(Cursor) 입니다.

2.5.1 쿼리(Query)

쿼리(Query)라는 단어를 우리 말로 표현할 때 주로 "질의"라는 용어를 사용합니다. "질의"라는 단어의 사전적 의미는, "의심나거나 모르는 점을 묻는 것"을 말합니다. 즉, 자신이 모르는 사실을 알기 위해, 누군가에게 질문하여 정보를 요청하는 것이 바로 "쿼리(Query)"라는 단어의 의미인 것이죠.


이제 관점을 데이터베이스로 옮겨보도록 하겠습니다. 데이터베이스에 저장된 데이터는, 그 정보를 획득하기 전까지는 사용자가 모르는(가지고 있지 않은) 정보입니다. 그래서 만약 그 정보를 얻기 위해서 데이터베이스 시스템에 정보를 요청한다면, 우리는 그것을 "데이터베이스에 쿼리(Query)"한다고 말할 수 있는 것입니다.


정리하자면, 쿼리(Query)란, 원하는 데이터를 얻기 위해 데이터베이스에 정보를 요청(Request)하는 것을 말하며, SQLite 데이터베이스에서 그 요청(Request)은 "SELECT" 문을 사용하여 작성할 수 있습니다.


그런데 앞서 살펴본 데이터 추가(INSERT), 수정(UPDATE), 삭제(DELETE)는 데이터베이스로 전달되는 단-방향 명령인데 반해, 조회(SELECT)를 위한 쿼리(Query)는 데이터베이스로부터 결과 데이터 전달이 필요한 양-방향 명령입니다. 그러므로 아무런 값도 리턴하지 않는 execSQL() 함수 대신, "SELECT" 문의 조건에 따라 선택된 레코드 집합(RecordSet)을 리턴하는 query() 함수 또는 rawQuery() 함수를 사용해야 합니다.


리턴 타입 메소드
Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
Cursor query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)
Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
Cursor queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal)
Cursor queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
Cursor rawQuery(String sql, String[] selectionArgs, CancellationSignal cancellationSignal)
Cursor rawQuery(String sql, String[] selectionArgs)
Cursor rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal)
Cursor rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable)

많은 종류의 쿼리(Query) 함수가 제공되긴 하지만 많은 경우에 "SELECT" 문 전체를 한번에 전달할 수 있는 rawQuery() 함수가 주로 사용됩니다.


또한 모든 쿼리(Query) 함수가 리턴하는 레코드 집합(RecordSet)은 Cursor 인터페이스 타입으로 전달됩니다.


참고로 레코드 집합(RecordSet)이라는 용어는 쿼리(Query) 결과에 포함된 레코드(Record)의 묶음(Set)을 말하는 것입니다. 보통 데이터를 쿼리(Query)한 결과는 하나 또는 하나 이상의 레코드(Record)를 포함하고 있는데, 이렇게 리턴된 결과 레코드들의 집합을 레코드 집합(RecordSet)이라고 지칭합니다.


또한 레코드 집합(RecordSet)을 다른 용어로 로우 집합(RowSet)이라고 부르기도 합니다. 이전 글에서 관계형 데이터베이스 용어에 대해 설명할 때 "로우(Row)=레코드(Record)"라는 것을 설명하였으므로 그 연관성을 쉽게 이해할 수 있으리라 생각합니다.

2.5.2 커서(Cursor)

일반적인 컴퓨팅 환경에서 커서(Cursor)란, 화면에 표시된 내용에서 사용자가 내용 입력 또는 확인을 위해, 사용자가 현재 주시하고 있는 위치에 대한 표시를 말합니다. 키보드 커서 또는 마우스 커서 등이 대표적이죠.
그리고 데이터베이스에서도 그 의미는 크게 다르지 않습니다. 데이터베이스의 쿼리 결과로 리턴된 데이터에서 현재 그 내용을 확인하고 있는 위치를 나타내는 정보를, 커서(Cursor)라는 용어를 사용하여 지칭합니다.


데이터베이스에 저장된 데이터를 쿼리하면 그 결과 데이터는, 한 개의 레코드만 가지거나, 또는 여러 개의 레코드가 포함된 레코드 집합(RecordSet)입니다. 이 때 레코드 집합(RecordSet)에 들어 있는 개별 레코드에 접근하여 그 값을 확인할 수 있는 기능을 제공해주는 것이 바로 커서(Cursor)가 하는 역할인 것입니다. 그래서 SQLiteDatabase가 제공하는 모든 쿼리(Query) 관련 함수들은 Cursor 타입을 리턴하도록 되어 있습니다.


안드로이드에서 데이터베이스 커서(Cursor) 기능은 Cursor(android.database.Cursor) 인터페이스에 정의되어 있습니다. (https://developer.android.com/reference/android/database/Cursor.html)

Cursor 인터페이스


Cursor 인터페이스에는 많은 수의 함수가 정의되어 있습니다. 하지만 대부분의 경우, 몇 개의 함수 사용만으로 쿼리 결과로 리턴된 데이터를 처리할 수 있습니다.

아래 예제 코드는 Cursor 인터페이스를 사용하여 쿼리 결과 데이터를 탐색하는 과정을 나타낸 것입니다.

    Cursor cursor = sqliteDB.rawQuery("SELECT ...", null) ;

    while (cursor.moveToNext()) {
        // 첫 번째 컬럼(Column)이 INTEGER 타입인 경우.
        int val = cursor.getInt(0) ;

        // 두 번째 컬럼(Column)의 타입이 TEXT 인 경우.
        String str = cursor.getText(1) ;

        // 세 번째 컬럼(Column)이 REAL 타입으로 선언된 경우.
        float real = cursor.getFloat(2) ;

        // 코드 계속...
    }
2.5.3 데이터베이스 데이터 조회하기. (SELECT)

앞서 설명한 쿼리(Query) 함수 및 커서(Cursor)를 사용하여 테이블에 저장된 모든 데이터를 조회하는 코드는 아래와 같습니다.

[STEP-6] SQLiteDatabase - 데이터 조회. ("SELECT ... " 문을 rawQuery()로 실행.)
    String sqlSelect = "SELECT * FROM ORDER_T" ;
    Cursor cursor = null ;

    cursor = sqliteDB.rawQuery(sqlSelect) ;
    while (cursor.moveToNext()) {
        // INTEGER로 선언된 첫 번째 "NO" 컬럼 값 가져오기.
        int no = cursor.getInt(0) ;

        // TEXT로 선언된 두 번째 "NAME" 컬럼 값 가져오기.
        String name = cursor.getText(1) ;

        // TODO : use no, name.
    }

만약 "SELECT" 문에 조건을 추가하여 특정 데이터만 조회하고자 한다면, 다른 SQL 문과 마찬가지로 "WHERE"를 추가하여 조건을 기술할 수 있습니다.

[STEP-6.1] SQLiteDatabase - 조건을 추가하여 데이터 조회. ("SELECT ... WHERE ..." 문을 rawQuery()로 실행.)
    // NAME 컬럼 값이 'ppotta'인 모든 데이터 조회.
    String sqlSelect = "SELECT * FROM ORDER_T WHERE NAME='ppotta'" ;

    Cursor cursor = sqliteDB.rawQuery(sqlSelect) ;
    while (cursor.moveToNext()) {
        // INTEGER로 선언된 첫 번째 "NO" 컬럼 값 가져오기.
        int no = cursor.getInt(0) ;

        // TEXT로 선언된 두 번째 "NAME" 컬럼 값 가져오기.
        String name = cursor.getText(1) ;

        // TODO : use no, name.
    }

2.6 SQLite 데이터베이스 테이블 삭제하기.

SQLite 데이터베이스에 만들어져 있는 테이블을 앱 실행 중 삭제하는 경우는 매우 드뭅니다. 하지만 앱의 기능이 변경되고 데이터베이스에 저장되는 데이터 구조가 복잡해지면, 기존에 만들어놓은 테이블만으로는 복잡해진 데이터를 처리하는 게 힘들어질 수 있습니다. 이 때 개발자가 선택할 수 있는 방법 중 하나는, 앱이 업그레이드된 후 처음 실행될 때 새로운 테이블을 만들어 기존 테이블의 데이터를 옮긴 다음, 기존 테이블은 삭제하는 것입니다.


테이블을 삭제하기 위해서는 "DROP TABLE" 문을 사용합니다.

[STEP-7] SQLiteDatabase - 테이블 삭제. ("DROP TABLE ... " 문을 execSQL()로 실행.)
    String sqlDropTbl = "DROP TABLE ORDER_T" ;

    sqliteDB.execSQL(sqlDropTbl) ;

"DROP TABLE" 문을 사용하여 테이블을 삭제할 때 주의해야 할 점은, 삭제하기 전 저장되어있던 데이터 또한 삭제와 동시에 모두 지워진다는 것과, 삭제된 데이터와 테이블은 다시 복구가 불가능하다는 것입니다. 그러므로 삭제하고자 하는 테이블에 중요한 데이터가 저장되어 있다면, 반드시 백업을 해둔 다음 테이블을 삭제해야 합니다.

3. 참고.

.END.


ANDROID 프로그래밍/DB , , , , , , , , , , , , , , , , , ,

  1. Blog Icon
    익명

    비밀댓글입니다

  2. 방문해 주셔서 감사드립니다.

  3. Blog Icon
    ㄱㄷ

    설명 진짜 최고네요

  4. 좋게 봐주셔서 감사합니다. ^^

  5. Blog Icon
    Gisys

    안녕하세요, 종합설계를 하고 있는 대학생입니다.
    제가 어플리케이션안에 범죄자의 신상정보를 알 수 있는 데이터베이스를 집어 넣고 싶은데
    위 코딩대로만 따라하면 되는건가요?
    코딩함에 있어서 도대체 데이터는 어디에다가 쌓는거며, 그 데이터를 조회하는 기능은
    데이터베이스의 기능은지 어플리케이션의 기능인지 그걸 알기가 힘듭니다..ㅠㅠ
    어떻게 해야 하는걸까요?

  6. 원하시는 기능을 구현하기 위해서는, 먼저 기초적인 자바 프로그래밍 언어에 대한 지식, 안드로이드 UI 프로그래밍, 마지막으로 데이터베이스에 대한 기초 지식을 갖추고 있어야 합니다.

    학과 과정에 프로그래밍과 관련된 내용이 포함되어 있지 않다면, 독학이나 학원을 통해 관련 내용을 습득하셔야겠죠.

    음, 정보통신공학 또는 컴퓨터공학 등을 전공하지 않으셨다면, 원하시는 기능을 구현하기가 쉽지 않으실 수 있습니다. 개인에 따라 책을 통해서 관련 지식을 이해하는 것이 어려울 수 있기 때문에,
    주변(지인, 과외, 학원 등등)의 도움을 받으시길 바랄게요.

    블로그의 질문과 답변만으로 기초적인 내용을 설명하고 이해시키기가 매우 어렵기 때문에, 실질적인 도움을 드리기가 힘들 것 같습니다.

    대신, 앱 개발 과정 중 안 풀리는 문제가 있거나 에러가 생기면 언제든 질문글 남겨주세요.
    최대한 도움 드릴 수 있도록 노력하겠습니다.

    감사합니다.

  7. Blog Icon
    Osori

    오타가 있네요
    IF NOT EXIST 를 IF NOT EXISTS로 고쳐야 될 것 같아요

  8. 앗! 오타가 있는 걸 아직까지도 인지하지 못했네요.
    잘못된 내용 지적해 주셔서 감사합니다. ^^

  9. Blog Icon
    ㅁㄴㅇ

    사랑합니다

  10. 워워~ 전 이미 임자가 있는 몸... ㅋㅋ
    방문해 주셔서 감사합니다. ^^

  11. Blog Icon
    짱짱

    사랑합니다...
    어뜩하면 좋죠 너무 이해가 잘가요ㅠㅠ

  12. 그 이유는 "짱짱"님의 좋은 머리와, 배우고자 하는 열정 때문이지... 본문의 내용이 좋아서가 아니라고 생각이 드는데요. ㅜㅜ

    제가 작성해놓고도, 돌아서서 다시 읽어보면 부끄럽기 짝이 없는 글들이네요.

    어쨌든 과분한 칭찬 감사드리고, 다른 글들도 많은 도움 되셨으면 좋겠습니다.

  13. Blog Icon
    굿굿

    이렇게 친절하게 자세히 설명해주셔서 너무 감사합니다. 많이 도움이 되었어요!

  14. 도움이 되어서 다행이네요.
    방문해 주셔서 감사합니다!

  15. 너무나도 소중한 포스팅 감사합니다
    덕분에 많은 도움을 받고 있습니다

  16. 칭찬과 격려의 글 남겨주셔서 감사합니다.
    좀 더 좋은 내용 정리할 수 있도록 노력하겠습니다.

    감사합니다.

  17. Blog Icon
    익명

    비밀댓글입니다

  18. 네. 링크 참조하시는 거라면 언제든 환영합니다.

    방문해 주셔서 감사합니다.

  19. Blog Icon
    이상윤

    안녕하세요 혹시 수정을 클릭했을때 같은 데이터가 없음을 표현하려면 무슨 코드를 써야 될까요?
    if (edtName.getText().toString().equals("")) {
    Toast.makeText(getApplicationContext(), "아름을 입력해주세요", Toast.LENGTH_SHORT).show();
    }
    else if(edtName.getText().toString().equals(null)) {
    Toast.makeText(getApplicationContext(), "데이터가 없습니다", Toast.LENGTH_SHORT).show();

    }
    else {
    sqlDB.execSQL("UPDATE groupTBL SET gNumber = (" + edtNumber.getText().toString() + ") WHERE gName = ('" + edtName.getText().toString() + "') ");
    Toast.makeText(getApplicationContext(), "수정됨",
    Toast.LENGTH_SHORT).show();
    }
    sqlDB.close();
    }

    이 코드에서는 일단 null을 넣어 봤는데 해결이 안되서요!

  20. 제가 질문 내용을 잘 이해하지 못하겠어요.

    같은 데이터가 있는지 없는지 DB에서 찾는 걸 말씀하시는건지, 데이터가 없을 때 그것을 화면에 어떻게 표시할 것인지를 말씀하시는건지...

    질문글에 올려주신 코드로 유추하기 조금 힘드네요.

    조금 더 구체적으로 질문글 올려주시면 답을 드리기가 더 수월할 것 같습니다.

    감사합니다.

  21. Blog Icon
    사랑합니다

    Cursor객체는 제가 알기로는 close()를 해주지 않으면, garbage collector로부터 자유롭기 때문에 계속해서 메모리를 차지할 우려가 있다고 하네요! 실제로 회사에서도 cursor.close();를 안써주니까, 시뮬레이터에선 문제가 없는데, 좀 구진 단말기로 테스트해보니까 1분마다, 디비로부터 데이터 받게 했더니 20분정도 돌아가다 튕기더라구요. 그게 close를안해서 났다고 직접적으로 써있진 않은데, 쓰고나서 안튕기는거보니 직간접적으로 영향이 어느 정도 있는것 같습니다. 그리고 궁금한점이.. cursor를 획득한 상태에서 db를 먼저 닫아버리면 cursor.get~()도 불가능해지는 건가요? 물론 그 정돈 스스로 알아보는게 좋겠어요. 라고 하시면 당연히 그게 맞는 말씀입니다 ㅋㅋ 근데 혹시라도 먼저 아시면 굳이 직접 해볼필요가 없지 싶어서요!

  22. 네. Cursor 객체의 close()!!!
    나중에 여유가 생기면, 관련 내용 정리해보도록 하겠습니다.

    그리고 DB를 먼저 닫으면 cursor 사용도 당연히 안되겠죠? Exception이 발생하겠네요.

    하지만.. 정확히 어떤 에러가 발생되는지는 저도 알지 못합니다. DB를 닫고 나서 cursor를 사용해 본적이 없어서요.

    질문글 올리시는 것을 보니, 개발에 대한 열정이 대단하시네요.
    제가 여유가 없어서 심도깊은 토론을 못하는 게 안타깝네요.

    나중에 여유가 생기고, 기회가 된다면 많은 의견 나눠보는 것도 좋을 것 같습니다.

    감사합니다.

  23. Blog Icon
    익명

    비밀댓글입니다

  24. sqlite 쓰세요. 두 번 쓰세요.

    이렇게 답을 드리는 것이, "sqlite가 매우 뛰어난 훌륭한 DBMS라서"는 아닙니다.
    sqlite는 안드로이드에서 기본적으로 사용할 수 있는 DBMS이며 사용 방법이 간단하기 때문에 초보자들이 접근할 수 있기 때문이죠.

    그렇다고 sqlite가 허접한 것도 아닙니다. DBMS로서의 견고한 기본기를 갖추고 있고, 아주 많고 복잡한 데이터가 아니라면 사용하는데 아무런 무리가 없는, 좋은 DBMS입니다.

    그리고 질문글에 올려주신 것과 같이 간단한 데이터 구조는 sqlite만으로 충분히 관리할 수 있으므로 sqlite를 적용하시고, 추후에 좀 더 다양한 DBMS로의 확장을 고려하시는 게 좋을 것 같습니다.

    감사합니다.

  25. 진짜 구글링하면서 수십개의 글을 보지만 뽀따님의 recipe블로그만큼 정리가 잘된 글들은 없네요. 항상 좋은 글에 감사드립니다. 초보개발자들에겐 정말 큰 힘이 됩니다

  26. 진짜 블로그하면서 수백개의 댓글을 보지만 novice님의 칭찬글만큼 격려가 되는 글들은 없네요. 항상 칭찬 글에 감사드립니다. 초보블로거들에겐 정말 큰 힘이 됩니다

    라는 답글 달아봅니다. ^^;;

    진심을 담아, 칭찬과 격려의 댓글 감사드립니다.

  27. Blog Icon
    감동받았습니다

    개발자를 위한 레시피라는 이름 답게, 없으면 안되는 블로그예요.
    막힐 때 마다 찾아오는데, 기본부터 차근차근 친절하게 알려주셔서 항상 큰 도움 받고 갑니다!
    좋은 글 감사합니다~^^ 항상 행복하세요!!

  28. 내용이 너무 적어서 부끄러울 따름입니다.
    방문해 주시고 댓글까지 남겨주셔서 감사합니다.

  29. Blog Icon
    굿보이

    혹시 소켓 통신으로 서버에서 SQLITE로 데이터를 관리하고 클라이언트에서 UI를 이용해 서버의 SQLITE를 삭제하거나 수정할 수 있나요??

  30. 답변이 늦었네요.
    건강 문제로 인해 꽤 오랜 시간 블로그에 신경을 못썼습니다.
    죄송합니다.

    질문하신 내용에 대한 답변은 "예" 입니다.
    하지만 전체적인 서버/클라이언트 구조와 역할에 대해서는 조금 더 고민이 필요합니다.

    소켓을 이용해 SQLITE를 삭제/수정한다는 질문으로 보아, DB와 NETWORK 관련 경험이 그리 많지 않으신 걸로 보여서요.

    주변의 경력자 또는 도움될만한 시스템 설계 관련 글을 통해 전체적인 흐름과 역할을 먼저 파악하시는 걸 추천드립니다.

    감사합니다.

  31. 선생님 최고에요

  32. 감사합니다!