środa, 16 września 2009

Sqlite - wprawka

Zainteresowałem się ostatnio kolejnym tematem, a mianowicie SQL. Do tej pory słyszałem, że to potężne narzędzie do zarządzania bazami danych, ale jakoś nigdy nie wziąłem się za siebie i nie przysiadłem do tego. Ostatnio mam trochę wolnego czasu, więc zajrzałem na stronę: www.w3schools.com gdzie znajduje się wiele materiałów o SQL i to w bardzo przystępnej formie. Po przejściu podstaw miałem okazję wystosować parę zapytań do treningowej bazy danych. Okazało się to łatwiejsze niż przypuszczałem.

Jako bibliotekę obsługującą bazę danych wybrałem sobie Sqlite3. Jest dość nieskomplikowana i nie trzeba stawiać żadnych serwerów SQL czy coś takiego. Instaluje się ją poleceniem:
sudo apt-get install libsqlite3-0 libsqlite3-dev
Bardzo prawdopodobne, że libsqlite3-0 będzie już w systemie gdyż korzysta z niej na przykład Firefox.

Teraz należy stworzyć nowy projekt, dodać do linkera /usr/lib/libsqlite3.so i napisać trochę kodu:
/* 
* File: main.cpp
* Author: daniel
*
* Created on 14 wrzesień 2009, 22:24
*/

#include <stdlib.h>
#include <sqlite3.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using std::cout;
using std::endl;

/*
*
*/

//pokazuje wiadomość błędu jeśli istnieje, a jeśli nie to wartość kodu
void handleReturnCode(int returnCode, char* ErrorMsg = NULL) {
if (returnCode != SQLITE_OK) {
if (ErrorMsg != NULL) {
std::cout << ErrorMsg << std::endl;
sqlite3_free(ErrorMsg);
} else {
std::cout << "Return code: " << returnCode << std::endl;
}
}
}

//struktura przechowująca dane o osobie
struct sOsoba {
std::string imie;
std::string nazwisko;
int rokUrodzenia;

sOsoba(const char* p_imie, const char* p_nazwisko, const int p_rokUrodzenia) {
imie = p_imie;
nazwisko = p_nazwisko;
rokUrodzenia = p_rokUrodzenia;
}
};

int main(int argc, char** argv) {
sqlite3* db;
int returnCode;

cout << "Otwieranie bazy danych: " << endl;
returnCode = sqlite3_open("test2.db", &db);
if (returnCode != 0) std::cout << returnCode << std::endl;
char* ErrorMsg;

cout << "Usunięcie tabeli tab" << endl;
returnCode = sqlite3_exec(db, "drop table if exists tab", NULL, NULL, &ErrorMsg);
handleReturnCode(returnCode, ErrorMsg);

cout << "Utworzenie tabeli tab" << endl;
returnCode = sqlite3_exec(db,
"create table tab (imie string, nazwisko string,
rokUrodzenia integer);",
NULL, NULL, &ErrorMsg);
handleReturnCode(returnCode, ErrorMsg);

cout << "Utworzenie listy osob" << endl;
std::vector<sOsoba> listaOsob;
listaOsob.push_back(sOsoba("Donald", "Tusk", 1957));
listaOsob.push_back(sOsoba("Lech", "Kaczyński", 1949));
listaOsob.push_back(sOsoba("Jarosław", "Kaczyński", 1949));
listaOsob.push_back(sOsoba("Grzegorz", "Napieralski", 1974));
listaOsob.push_back(sOsoba("Waldemar", "Pawlak", 1959));
listaOsob.push_back(sOsoba("Grzegorz", "Schetyna", 1963));

//Dodawanie kolejnych nazwisk
std::vector<sOsoba>::iterator it = listaOsob.begin();
while (it != listaOsob.end()) {
cout << "Dodawanie " << it->imie<< " " << it->nazwisko << endl;
std::stringstream query;
query << "insert into tab values (\""
<< it->imie
<<"\", \""
<< it->nazwisko
<< "\", "
<< it->rokUrodzenia <<");";
returnCode = sqlite3_exec(db, query.str().c_str(), NULL, NULL, &ErrorMsg);
handleReturnCode(returnCode, ErrorMsg);
it++;
}

char** result;
int nRows, nCols;
//zapytanie o polityków którzy urodzili się po 1960
sqlite3_get_table(db,
"select nazwisko, rokUrodzenia
from tab
where rokUrodzenia > 1960
order by rokUrodzenia asc",
&result, &nRows, &nCols, &ErrorMsg);
cout << "Result: [" << nRows << ", " << nCols << "]" << endl;
//zerowy wiersz to nagłówki tabeli, a reszta to wyniki, więc rzędów jest nRows + 1
for (int i = 0; i <= nRows; i++) {
for (int j = 0; j < nCols; j++) {
cout << result[i * nCols + j] << "\t";
if (j > 0 && i>0) {
//dla sprawdzenia czy da się łatwo skonwertować liczbę
int rok = atoi(result[i * nCols + j]);
cout << "\t skonwertowany rok: " << rok;
}
}
cout << endl;
}
//zwalnianie pamięci przydzielonej dla tabeli
sqlite3_free_table(result);

cout << "Zamykanie bazy danych" << endl;
sqlite3_close(db);
//wywołanie polecenia systemowego eksportującego tabelę tab do pliku csv
system("sqlite3 -csv test2.db \"select * from tab;\" > wyjscie.csv");
cout << endl;
//wyświetlenie zawartości pliku csv w konsoli
system("cat wyjscie.csv");

return (EXIT_SUCCESS);
}