SQLite

Posted by 겨울에
2011. 2. 4. 00:58 scrap/ Android

이번 강좌가 올라오기까지도 꽤 많은 시간이 걸렸습니다. ^^; 제 게으름(???)... 이 아니라, 사실 데이터베이스 쪽을 강좌에서 다루려고 하다 보니 어디부터 설명해야 쉬울까... 고민도 좀 했었고, 저도 공부를 하다가 막히는 부분이 좀 있어서 그것 때문에 계속 인터넷이랑 책을 찾아보기도 했었구요^^;;;

어쨌든, 데이터베이스를 다루는 어플리케이션을 제작하기 전에, 데이터베이스에 대한 기초 지식과 간단한 SQL문은 알고 있어야 앞으로 나올 코드들을 이해하는 데 어려움이 없을 것입니다. 우리가 어떤 프로그래밍 언어를 모른다면, 그 언어로 제작된 코드를 읽기 어려운 것과 마찬가지로, 간단하기는 하지만 데이터베이스를 다루는 하나의 언어라고 볼 수 있는 SQL문을 알아야 데이터베이스를 다룰 수 있을 것입니다.

데이터베이스?
데이터베이스는 여러 가지 데이터들이 일목요연하게 정리되어있는 하나의 "리스트" 정도로 이해하시면 됩니다. 마치 엑셀 시트에 들어가있는 전화번호부 정도를 연상하시면 되겠네요. 사실, 데이터베이스 하면 가장 기초적인 테이블부터 시작하여 별의별 용어와 개념이 있지만, 이 강좌에서는 안드로이드 어플리케이션에서 주로 쓰이는 테이블 단위까지만 소개하도록 하겠습니다.

테이블(Table) 이란?
테이블이란, 서로 관련 있는 정보들을 묶어 놓은 것입니다. 조금 더 구체적으로 말하면, 자신이 보고자 하는 항목들로 열을 구성해놓은 것이라 할 수 있습니다. 예를 들면, 주소록에서 이름, 전화번호만을 묶어서 한 테이블을 만들 수도 있고, 이름, 이메일주소를 묶을 수도 있으며, 이름, 전화번호, 이메일주소 모두를 묶어서 한 테이블을 만들 수도 있습니다.

테이블 생성하기
create table notes (_id integer primary key autoincrement, title text not null, body text not null);

create table notes
"notes"라는 이름을 가진 테이블을 생성합니다. 이후 괄호 안의 항목들은 테이블을 구성하는 열(Column)과 열들의 속성을 지정해주는 구문입니다.

_id integer primary key autoimcrement
정수형 데이터를 갖는 _id라는 이름을 가지는 열(필드)을 생성합니다. primary key는 이 열이 기준열이 됨을 의미합니다. 이 기준열이 되는 열의 내용은 각 레코드별로 달라야 합니다. autoincrement는 레코드가 추가될 때마다 해당 열의 데이터가 자동으로 증가함을 나타냅니다. 

title text not null, body text not null
text형 데이터를 갖는 title과 text 열을 생성합니다. 이 두 열(필드)는 값이 항상 있어야(not null) 합니다.

테이블 삭제하기
drop table if exists notes

"notes"라는 테이블이 있을 경우(if exists) 테이블을 삭제합니다.


SQL문은 생각보다 구문 자체는 "읽으면 이해가 되는"정도라 그다지 부담갖지 않으셔도 됩니다. 데이터베이스를 다루는 SQL구문은 여러 종류가 있지만, 안드로이드 어플리케이션에서 실질적으로 구문 전체를 다 써줘야 하는 것은 거의 위의 두 가지 뿐이므로, 다른 것들은 다음 강좌에서 설명하도록 하겠습니다. 

----------------------------------------------------------------------------------------------------------------

이번 강좌에서는 안드로이드 어플리케이션 내에서 실제로 데이터베이스를 다루는 방법에 대하여 알아보도록 하겠습니다. 데이터베이스는 워낙에 양도 많고, 이해하고 넘어가야 하는 것들도 많아서 강좌를 진행하는데 어려운 점이 한둘이 아니네요. -_-;;
차근차근~ 들어가도록 하겠습니다.

다른 강좌도 마찬가지지만, 데이터베이스 쪽 강좌를 보실 때는 절대 서두르지 마세요. 전 서둘러서 하다가 -_-;; 오히려 머리만 복잡해지고! 되는 건 없고! 한참동안 방황했었답니다~ ^^;; 마치 코드의 늪에 빠진 기분이 들어군요;; 분명히 맞게 입력한 것 같은데 에러나고...-_-;; 게다가 에러의 대부분이 런타임 에러여서 도통 무엇 때문인지 감도 잘 안오고 말이죠. ㄱ-..

주저리는 여기서 마치도록 하고, 본격적으로 강좌에 들어가도록 하겠습니다.

데이터베이스의 간단한 구성 : 테이블, 레코드, 필드

데이터베이스를 구성하는 요소는 참으로 다양하지만, 자주 쓰이는 것들은 기본적인 것들 몇 가지들입니다. 

1. 테이블
테이블은 데이터들이 저장되어 있는 공간입니다.




2. 필드
필드는 각 항목의 "분류" 정도로 보면 되겠습니다. 예를 들면, 전화번호부의 이름, 전화번호, 이메일주소 등이 필드에 해당합니다.




3. 레코드
레코드는 각 필드에 해당하는 데이터값의 집합입니다. 위의 그림에서 보면 _id값은 2, name은 android, phone은 23423을 가지는 하나의 데이터를 레코드라 부릅니다. 전화번호부를 예로 들자면, 한 사람이 가지고 있는 데이터들(이름, 전화번호, 이메일주소)가 레코드가 됩니다.





안드로이드에서 데이터베이스 다루기 : 데이터베이스 어댑터

데이터베이스를 생성하고, 열고, 데이터베이스에 데이터를 넣고, 쿼리를 통해서 데이터베이스에서 정보를 받아오는 작업은 
SQLiteDatabase(android.database.sqlite.SQLiteDatabase) 와
SQLiteOpenHelper(android.database.sqlite.SQLiteOpenHelper) 내의 메소드를 통해 처리됩니다. 

SQLiteDatabase 클래스에서는 데이터베이스를 다루는 작업(추가, 삭제, 수정, 쿼리)를 담당하고, SQLiteOpenHelper 클래스 에서는 데이터베이스의 생성, 열기, 업그레이드를 담당합니다. 이러한 클래스 내의 메소드를 통해 직접 데이터베이스를 생성하고, 수정하고, 쿼리를 수행할 수도 있지만 이렇게 할 경우 코드상에 데이터베이스 구조들도 다 드러나게 되고, 실제로 코드를 볼 때에도 이 코드가 무엇을 하는 코드인지 바로 보기 불편합니다. 그래서, 일반적으로는 내가 사용할 데이터베이스에 맞게끔 데이터베이스 어댑터를 만들고 어댑터를 통해 데이터베이스를 관리합니다.



데이터베이스에서 원하는 자료를 받아오기 : 쿼리(query; 질의)

데이터베이스를 생성하고 자료를 추가하는 것 못지않게 중요한 것이 바로 자신이 원하는 데이터베이스를 가져오는 것입니다. 이는 쿼리(Query; 질의)를 통해 이루어집니다. 질의 결과는 Cursor객체 형태로 반환됩니다.

public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, 
String groupBy, String having, String orderBy, String limit) 

table  질의를 수행할 테이블 이름입니다.
columns  자료를 받아올 필드들입니다. null을 입력하면 모든 필드를 반환합니다.
selection  SQL의 "where" 구문에 해당되는 조건을 입력합니다. 조건이 많을 경우, ?로 대체합니다.
selectionArgs  selection을 ?로 지정하였을 경우, 그 조건들을 입력합니다.
groupBy  SQL의 "group by"구문에 해당합니다.
having  groupBy를 지정했을 경우, 그 조건을 넣어줍니다.
orderBy  결과값 정렬 방식을 지정합니다. null을 입력하면 기본 정렬을 수행합니다.
limit  결과값의 개수를 제한합니다.

(API : android.database.sqlite.SQLiteDatabase)
위에서 소개된 형태 외에도 다른 형태로 2가지 메소드가 있으니 참조하시면 됩니다.

예제)
Cursor all = myDB.query("data", null, null, null, null, null, null, null);  // 모든 레코드를 반환하는 쿼리를 실행합니다.
Cursor sel = myDB.query("data", "name = google", null, null, null, null, null, null);
// 이름이 google인 레코드를 반환하는 쿼리를 실행합니다.



데이터베이스 값을 가지는 객체, Cursors와 ContentValues

데이터베이스 내에서 값을 추가하고, 삭제하고, 수정하는 작업돠는 별도로, 데이터베이스에 저장된 값을 코드 내로 가져와야 하거나, 코드 내에서 받은 값들을 데이터베이스에 추가시키는 과정이 있습니다. 우선, 데이터베이스의 데이터를 코드 내로 가져오는 것부터 보도록 하겠습니다.

데이터베이스 -> 코드 데이터 가져오기 : Cursor

데이터베이스에서 자료를 가져올 때는 그 자료가 특정한 값 하나 (예:이름)이 될 수도 있고, 레코드가 될 수도 있고, 혹은 전체 데이터가 될 수도 있습니다. 이런 자료들을 받아오기 위해서 Cursor 인터페이스를 사용합니다. 
커서는 쿼리(질의) 결과로 나온 레코드들을 가리키는, 말 그대로 마우스 "커서" 처럼 특정 레코드를 가리키는 역할을 합니다. 결과 레코드가 여러 개일 경우, 커서를 이리저리 움직이면서 여러 레코드들의 데이터들을 받아올 수 있습니다.


데이터베이스에서 커서는 특정 레코드를 가리키는 역할을 합니다.


Cursor 인터페이스의 주요 메소드는 다음과 같습니다.
* moveToFirst  커서가 쿼리(질의) 결과 레코드들 중에서 가장 처음에 위치한 레코드를 가리키도록 합니다.
* moveToNext  다음 레코드로 커서를 이동합니다.
* moveToPrevious  이전 레코드로 커서를 이동합니다.
* getCount  질의 결과값(레코드)의 갯수를 반환합니다.
* getColumnIndexOrThrow  특정 필드의 인덱스값을 반환하며, 필드가 존재하지 않을경우 예외를 발생시킵니다.
* getColumnName  특정 인덱스값에 해당하는 필드 이름을 반환합니다.
* getColumnNames  필드 이름들을 String 배열 형태로 반환합니다.
* moveToPosition  커서를 특정 레코드로 이동시킵니다.
* getPosition  커서가 현재 가리키고 있는 위치를 반환합니다.

커서에서 데이터를 받아올 때에는,  get<데이터타입>(필드 인덱스) 메소드를 사용합니다.
위의 그림과 같은 질의 결과에서 이름을 받아오고 싶다면, 우선 이름 필드(name)의 인덱스를 알야아 합니다. 필드 인덱스는 일반적인 인덱스들과 마찬가지로 0부터 시작하므로 _id의 필드 인덱스는 0, name은 1, phone은 2가 되겠습니다. 참고로, 위 데이터베이스의 각 필드별 데이터 타입은 _id는 long, name은 String, phone은 long입니다.

필드 인덱스는 알았고, 받아올 데이터 타입이 String이므로 현재 레코드에서 이름을 받아오기 위해서는 getString(int ColumnIndex)메소드를 사용하면 됩니다. 즉, getString(1)이 되겠죠. 만약, 이름이 아니라 전화번호를 받아오고 싶다면 getLong(1)을 사용하면 되겠죠?

example
String name = result.getString(1);             // 레코드로부터 이름을 받아옵니다.
long phone = result.getLong(2);               // 레코드로부터 전화번호를 받아옵니다.

다른 데이터타입을 불러오는 메소드는 여기(http://developer.android.com/reference/android/database/Cursor.html)를 참조하세요.



코드 -> 데이터베이스에 자료 입력하기 : ContentValues

(android.content.ContentValues)
위의 Cursor와는 반대로, 자료를 데이터베이스에 입력하기 위해서 ContentValues 객체를 데이터베이스의 레코드와 동일하게 사용합니다. ContentValues 객체에 데이터베이스 테이블에 맞게 자료를 입력한 후, SQLiteDatabase 클래스의 insert()메소드를 사용하여 데이터베이스에 새로운 레코드를 추가합니다.

Cursor 형태로 된 쿼리 결과에서 데이터를 가져오는 것과 비슷하게, put(_필드 이름_, _입력할 값_)을 이용합니다.

// 필요한 데이터를 입력합니다.
ContentValues newValues = new ContentValues();
newValues.put("name", "구글");
newValues.put("phone", "1234567");
// 레코드를 추가합니다.
myDB.insert("data", null, newValues);

데이터베이스에 레코드를 추가하는 메소드인 insert()메소드에 대해 자세한 정보는 여기(http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert(java.lang.String, java.lang.String, android.content.ContentValues))를 참고하세요. 

'scrap >  Android' 카테고리의 다른 글

Android File List  (0) 2011.02.04
Container Scroll  (0) 2011.02.04
android - 다수의 Insert 수행시 속도 향상을 위한 팁  (0) 2011.02.03
android 가로모드 막기 & 세로모드 막기  (0) 2011.02.03
android EditText tip  (0) 2011.02.03