В этом уроке:
- читаем данные из связанных таблиц
- используем rawQuery
Мы достаточно подробно разобрали метод query. Но не рассмотрели, как с его помощью выполнять запросы для связанных таблиц. Создадим простое приложение, которое будет делать запрос из двух таблиц и выводить результат в лог. Таблицы будут people и position. В первую (people) запишем список людей, во вторую (position) – список должностей. И для каждого человека в people будет прописан id должности из position.
Создадим проект:
Project name: P0371_SQLiteInnerJoin
Build Target: Android 2.3.3
Application name: SQLiteInnerJoin
Package name: ru.startandroid.develop.p0371sqliteinnerjoin
Create Activity: MainActivity
Экран вообще использовать не будем, поэтому main.xml даже не трогаем. Открываем MainActivity.java и пишем код:
package ru.startandroid.develop.p0371sqliteinnerjoin; import android.app.Activity; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.Bundle; import android.util.Log; public class MainActivity extends Activity { final String LOG_TAG = "myLogs"; // данные для таблицы должностей int[] position_id = { 1, 2, 3, 4 }; String[] position_name = { "Директор", "Программер", "Бухгалтер", "Охранник" }; int[] position_salary = { 15000, 13000, 10000, 8000 }; // данные для таблицы людей String[] people_name = { "Иван", "Марья", "Петр", "Антон", "Даша", "Борис", "Костя", "Игорь" }; int[] people_posid = { 2, 3, 2, 2, 3, 1, 2, 4 }; /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Подключаемся к БД DBHelper dbh = new DBHelper(this); SQLiteDatabase db = dbh.getWritableDatabase(); // Описание курсора Cursor c; // выводим в лог данные по должностям Log.d(LOG_TAG, "--- Table position ---"); c = db.query("position", null, null, null, null, null, null); logCursor(c); c.close(); Log.d(LOG_TAG, "--- ---"); // выводим в лог данные по людям Log.d(LOG_TAG, "--- Table people ---"); c = db.query("people", null, null, null, null, null, null); logCursor(c); c.close(); Log.d(LOG_TAG, "--- ---"); // выводим результат объединения // используем rawQuery Log.d(LOG_TAG, "--- INNER JOIN with rawQuery---"); String sqlQuery = "select PL.name as Name, PS.name as Position, salary as Salary " + "from people as PL " + "inner join position as PS " + "on PL.posid = PS.id " + "where salary > ?"; c = db.rawQuery(sqlQuery, new String[] {"12000"}); logCursor(c); c.close(); Log.d(LOG_TAG, "--- ---"); // выводим результат объединения // используем query Log.d(LOG_TAG, "--- INNER JOIN with query---"); String table = "people as PL inner join position as PS on PL.posid = PS.id"; String columns[] = { "PL.name as Name", "PS.name as Position", "salary as Salary" }; String selection = "salary < ?"; String[] selectionArgs = {"12000"}; c = db.query(table, columns, selection, selectionArgs, null, null, null); logCursor(c); c.close(); Log.d(LOG_TAG, "--- ---"); // закрываем БД dbh.close(); } // вывод в лог данных из курсора void logCursor(Cursor c) { if (c != null) { if (c.moveToFirst()) { String str; do { str = ""; for (String cn : c.getColumnNames()) { str = str.concat(cn + " = " + c.getString(c.getColumnIndex(cn)) + "; "); } Log.d(LOG_TAG, str); } while (c.moveToNext()); } } else Log.d(LOG_TAG, "Cursor is null"); } // класс для работы с БД class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context) { super(context, "myDB", null, 1); } public void onCreate(SQLiteDatabase db) { Log.d(LOG_TAG, "--- onCreate database ---"); ContentValues cv = new ContentValues(); // создаем таблицу должностей db.execSQL("create table position (" + "id integer primary key," + "name text," + "salary integer" + ");"); // заполняем ее for (int i = 0; i < position_id.length; i++) { cv.clear(); cv.put("id", position_id[i]); cv.put("name", position_name[i]); cv.put("salary", position_salary[i]); db.insert("position", null, cv); } // создаем таблицу людей db.execSQL("create table people (" + "id integer primary key autoincrement," + "name text," + "posid integer" + ");"); // заполняем ее for (int i = 0; i < people_name.length; i++) { cv.clear(); cv.put("name", people_name[i]); cv.put("posid", people_posid[i]); db.insert("people", null, cv); } } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } }
Разбираем код. Сначала идут несколько массивов с данными для таблиц. Обратите внимание, для должностей мы будем указывать id при заполнении таблиц. Это сделано для того, чтобы мы знали эти номера и могли их использовать в таблице людей для указания id должности.
В методе Activity onCreate мы создаем объект для управления БД и подключаемся к БД. Далее используя знакомый нам query выводим в лог данные из таблиц position и people.
Для вывода объединения таблиц используем rawQuery. Это несложный метод, который принимает на вход SQL-запрос и список аргументов для условия WHERE (если необходимо). Мы сформировали запрос на объединение двух таблиц и вывода имени, должности и зарплаты человека. Условие выборки: ЗП должна быть больше 12000. Мы использовали аргументы для формирования условия.
Далее снова выводим объединение таблиц, но используем обычный query. В table записываем все таблицы, их алиасы и условие JOIN. В columns – все нужные поля с использованием алиасов. Ну и в selection и selectionArgs пишем условие выборки – ЗП меньше 12000.
Наш метод logCursor получает на вход Cursor и выводит в лог все содержимое. Тут все знакомо с прошлых уроков.
В классе DBHelper кодим создание таблиц и, на этот раз, здесь же их наполнение данными.
Все сохраним и запустим. Смотрим лог:
--- onCreate database ---
--- Table position ---
id = 1; name = Директор; salary = 15000;
id = 2; name = Программер; salary = 13000;
id = 3; name = Бухгалтер; salary = 10000;
id = 4; name = Охранник; salary = 8000;
--- ---
--- Table people ---
id = 1; name = Иван; posid = 2;
id = 2; name = Марья; posid = 3;
id = 3; name = Петр; posid = 2;
id = 4; name = Антон; posid = 2;
id = 5; name = Даша; posid = 3;
id = 6; name = Борис; posid = 1;
id = 7; name = Костя; posid = 2;
id = 8; name = Игорь; posid = 4;
--- ---
Вывели данные по таблицам раздельно.
--- INNER JOIN with rawQuery---
Name = Иван; Position = Программер; Salary = 13000;
Name = Петр; Position = Программер; Salary = 13000;
Name = Антон; Position = Программер; Salary = 13000;
Name = Борис; Position = Директор; Salary = 15000;
Name = Костя; Position = Программер; Salary = 13000;
--- ---
Вывели данные из rawQuery. ЗП > 12000
--- INNER JOIN with query---
Name = Марья; Position = Бухгалтер; Salary = 10000;
Name = Даша; Position = Бухгалтер; Salary = 10000;
Name = Игорь; Position = Охранник; Salary = 8000;
--- ---
Вывели данные из query. ЗП < 12000
Как видите, запросы из связанных таблиц в SQLite – не проблема и ничем не отличается от обычных БД.
Что использовать rawQuery или query – решать вам и зависит от ситуации. Хотя, навскидку я не могу придумать преимущества одного над другим в той или иной ситуации. Но наверно они есть.
Данные по ЗП и должностям являются выдуманными, любое совпадение – случайно. И, разумеется, ничего против бухгалтеров и охранников я не имею ))
На следующем уроке:
- используем транзакции при работе с БД
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня