방마리 2021. 11. 23. 23:08

SQLite의 기본

데이터베이스의 기본 개념

SQLite 학습에 앞서 데이터베이스(특히 관계형 데이터베이스)의 기본 개념과 용어를 이해해야한다.

SQLite를 운영하기 위한 최소한의 내용만을 살펴본다.

 

데이터베이스의 정의

데이터베이스는 '대용량의 데이터 집합을 체계적으로 구성해놓은 것'으로 정의할 수 있다.

 

지속적으로 대량으로 발생하는 다양한 형태의 정보를 보관하려면 기존의 파일 시스템으로는 한계가 있기 때문에 고안된 것이 바로 데이터를 보관·관리하는 데이터베이스 시스템이다.

 

데이터베이스는 여러 사용자나 시스템이 서로 공유할 수 있어야 한다.

 

데이터베이스 관리 시스템(DataBase Management System, DBMS)은 데이터 베이스를 관리하는 시스템 또는 소프트웨어를 말한다.

 

유명한 DBMS로는 마이크로소프트의 SQL Server, Access / 오라클의 Oracle Database, MySQL / IBM의 DB2 등이 있다.

 

관계형 데이터베이스

DBMS는 크게 계층형(hierarchical), 망형(network), 관계형(relational), 객체지향형(object-oriented), 객체관계형(object-relational) 등의 유형으로 구분된다.

 

관계형 DBMS(RDBMS)를 가장 많이 사용하고, 일부 분야에서 객체지향형 또는 객체관계형 DBMS를 활용한다.

 

위에서 언급한 유명한 DBMS들은 모두 관계형 DBMS이며, SQLite역시 마찬가지이다.

 

관계형 DBMS의 가장 큰 단점은 시스템 자원을 많이 차지하여 시스템이 전반으로 느려질 수밖에 없다는 점이지만 최근 HW가 급속하게 발전하여 많이 보완되었다.

 

(모바일 환경에서 동작하는) SQLite는 RDBMS의 단점 극복을 위해 동시 접근이나 대용량 데이터 관리에 제한을 두지만 RDBMS의 표준형 SQL이나 개념은 동일하게 적용된다.

 

데이터베이스 관련 용어

데이터베이스 구축을 위해서는 '데이터베이스 모델링'을 먼저 해야한다.

'데이터베이스 모델링'이란 현실 세계에서 사용되는 데이터를 DBMS 안에 어떻게 옮겨놓을지를 결정하는 과정이다.

 

관련 용어는 아래와 같이 정리할 수 있다.

 

 

데이터 : 하나하나의 단편적인 정보를 뜻한다.
테이블 : 데이터가 표 형태로 표현된 것을 말한다.
데이터베이스 (DB) : 테이블이 저장되는 장소로 주로 원통 모양으로 표현한다. 각 데이터베이스는 고유한 이름을 가져야 한다.
DBMS : 데이터베이스를 관리하는 시스템 또는 소프트웨어를 말한다.
열 (column 또는 field) : 각 테이블은 1개 이상의 열로 구성된다.
열 이름 : 각 열을 구분하는 이름이다. 열 이름은 각 테이블 안에서 중복되지 않아야 한다.
데이터 형식 : 열의 데이터 형식을 말한다. 예를 들어 '사람 이름' 열은 숫자가 아닌 문자 형식이어야 한다. 또한 '출생 연도' 열은 숫자(정수) 형식이어야 한다.
행 (row) : 실제 데이터를 말한다.
SQL (Structured Query Language, 구조화된 질의 언어) : 사용자와 DBMS가 소통하기 위한 언어이다.

 

 

SQLite에서의 데이터베이스 구축

 

adb root
adb shell
cd /data/data/com.cookandroid.project12_1
ls -l
mkdir databases
cd databases
pwd

root 권한으로 adb 재시작

shell 실행 (ADB 내부 진입)

프로젝트 디렉터리 진입 후 databases 디렉터리 생성

 

데이터베이스 생성

sqlite3 naverDB

naverDB 이름의 데이터베이스가 생성되면서, SQL 문을 사용할 수 있게된다.

현재 naverDB 내부는 아직 비어있으며, 만약 이미 존재했다면 naverDB를 사용할 수 있는 상태가 된다.

 

테이블 생성

테이블을 생성하는 SQL문의 형식은 아래와 같다.

CREATE TABLE 테이블이름 (열이름1 데이터형식, 열이름2 데이터형식, …);

 

실제 코드는 아래와 같다.

CREATE TABLE userTable (id char(4), userName char(15), email char(15), birthYear int);
.table
.schema userTable

테이블 생성 및 확인 코드

 

 

데이터 입력

생성한 테이블에 행 데이터를 입력하는 SQL문의 형식은 아래와 같다.

INSERT INTO 테이블이름 VALUES(값1, 값2, …);
INSERT INTO userTable VALUES('john', 'John Bann', 'john@naver.com', 1990);
INSERT INTO userTable VALUES('kim', 'Kim Chi', 'kim@naver.com', 1992);
INSERT INTO userTable VALUES('lee', 'Lee Pal', 'lee@naver.com', 1988);
INSERT INTO userTable VALUES('park', 'Park Su', 'park@naver.com', 1980);

 

데이터 조회·활용

데이터 조회 및 활용에 사용하는 SQL문은 SELECT인데, 주로 WHERE 절과 함께 사용한다.

SELECT 열이름1, 열이름2, … FROM 테이블이름 WHERE 조건;

 

.header on
.mode column
SELECT * FROM userTable;
SELECT id, birthYear FROM userTable WHERE birthYear <= 1990;
SELECT * FROM userTable WHERE id = 'park';

1, 2열은 보기 좋게 출력하기 위한 명령어이다.

모든 작업 완료 후에는 .exit 명령으로  SQLite를 종료한다.

 

 

SQLite의 활용

안드로이드 프로그래밍에 SQLite를 활용하는 방법을 알아보자.

 

SQLite 프로그래밍

안드로이드 앱 개발을 위한 SQLite 동작 방식

안드로이드 앱에서 SQLite 사용시 일반적으로 SQLiteOpenHelper 클래스, SQLite Database 클래스, Cursor 인터페이스를 이용한다.

각 관계는 아래와 같다.

 

또한 각 클래스에서 주로 사용되는 메소드는 아래의 표와 같다.

 

실습 12-2 가수 그룹 관리 DB 앱 만들기

package com.cookandroid.project12_2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    myDBHelper myHelper;
    EditText edtName, edtNumber, edtNameResult, edtNumberResult;
    Button btnInit, btnInsert, btnSelect;
    SQLiteDatabase sqlDB;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("가수 그룹 관리 DB");

        edtName = (EditText)findViewById(R.id.edtName);
        edtNumber = (EditText)findViewById(R.id.edtNumber);
        edtNameResult = (EditText)findViewById(R.id.edtNameResult);
        edtNumberResult = (EditText)findViewById(R.id.edtNumberResult);
        btnInit = (Button)findViewById(R.id.btnInit);
        btnInsert = (Button)findViewById(R.id.btnInsert);
        btnSelect = (Button)findViewById(R.id.btnSelect);

        //<초기화> 버튼을 클릭했을 때 동작하는 리스너
        myHelper = new myDBHelper(this);
        btnInit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sqlDB = myHelper.getWritableDatabase();                   // groupDB를 쓰기용 데이터베이스로 열기
                myHelper.onUpgrade(sqlDB, 1, 2);    // groupTBL이 있으면 삭제한 후 새로 생성
                sqlDB.close();
            }
        });

        //<입력>을 클릭했을 때 에디트텍스트의 값이 입력되는 리스너
        btnInsert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sqlDB = myHelper.getWritableDatabase();                                                                                             // groupDB를 쓰기용으로 열기
                sqlDB.execSQL("INSERT INTO groupTBL VALUES ( '"  + edtName.getText().toString() +"', " + edtNumber.getText().toString() + ");");    // EditText에 입력된 값으로 Insert SQL문을 생성하여 execSQL()로 실행
                sqlDB.close();
                Toast.makeText(getApplicationContext(), "입력됨", 0).show();
            }
        });

        //<조회>를 클릭했을 때 테이블에 입력된 내용이 모두 아래쪽 EditText에 출력되는 리스너
        btnSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sqlDB = myHelper.getReadableDatabase();

                // 커서 선언 및 모든 테이블 조회 후 커서에 대입
                // 테이블에 입력된 모든 행 데이터가 커서 변수에 들어 있는 상태가 되며, 첫 번째 행을 가리키게 된다.
               Cursor cursor;
                cursor = sqlDB.rawQuery("SELECT * FROM groupTBL;", null);

                String strNames = "그룹 이름" + "\r\n" + "------" + "\r\n";
                String strNumbers = "인원" + "\r\n" + "------" + "\r\n";

                // 행 데이터 개수만큼 반복하며 행의 각 열 데이터를 문자열 변수에 추가한다.
                while(cursor.moveToNext()){
                    strNames += cursor.getString(0) + "\r\n";
                    strNumbers += cursor.getString(1) + "\r\n";
                }

                edtNameResult.setText(strNames);
                edtNumberResult.setText(strNumbers);

                cursor.close();
                sqlDB.close();
            }
        });
    }
    // SQLiteOpenHelper 클래스를 상송받는 myDBHelper 클래스를 정의한다.
    public class myDBHelper extends SQLiteOpenHelper {

        // 생성자를 정의한다. super의 두 번쨰 파라미터에는 새로 생성될 데이터베이스의 파일명을 지정한다. 마지막 파라미터는 데이터베이스 버전으로 처음에는 1을 지정한다.
        public myDBHelper(Context context) {
            super(context, "groupDB", null, 1);
        }

        @Override
        public void onCreate(SQLiteDatabase db){
            // 테이블을 생성한다. onUpgrade() 에서 호출되거나, 데이터를 입력할 때 혹은 테이블이 없을 때 처음 한 번 호출된다.
            db.execSQL("Create TABLE groupTBL( gName CHAR(20) PRIMARY KEY, gNumber INTEGER);");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
            // 테이블을 삭제하고 새로 생성한다. (초기화)
            db.execSQL("DROP TABLE IF EXISTS groupTBL");
            onCreate(db);
        }
    }
}