Работа с базами данных SQLite
В Android имеется встроенная поддержка одной из распространенных систем управления базами данных — SQLite. Для этого в пакете android.database.sqlite определен набор классов, которые позволяют работать с базами данных SQLite. И каждое приложение может создать свою базу данных.
Чтобы использовать SQLite в Android, надо создать базу данных с помощью выражение на языке SQL. После этого база данных будет храниться в каталоге приложения по пути:
ОС Android по умолчанию уже содержит ряд встроенных бад SQLite, которые используются стандартными программами — для списка контактов, для хранения фотографий с камеры, музыкальных альбомов и т.д.
Основную функциональность по работе с базами данных предоставляет пакет android.database . Функциональность непосредственно для работы с SQLite находится в пакете android.database.sqlite .
База данных в SQLite представлена классом android.database.sqlite.SQLiteDatabase . Он позволяет выполнять запросы к бд, выполнять с ней различные манипуляции.
Класс android.database.sqlite.SQLiteCursor предоставляет запрос и позволяет возвращать набор строк, которые соответствуют этому запросу.
Класс android.database.sqlite.SQLiteQueryBuilder позволяет создавать SQL-запросы.
Сами sql-выражения представлены классом android.database.sqlite.SQLiteStatement , которые позволяют с помощью плейсхолдеров вставлять в выражения динамические данные.
Класс android.database.sqlite.SQLiteOpenHelper позволяет создать базу данных со всеми таблицами, если их еще не существует.
В SQLite применяется следующая система типов данных:
INTEGER : представляет целое число, аналог типу int в java
REAL : представляет число с плавающей точкой, аналог float и double в java
TEXT : представляет набор символов, аналог String и char в java
BLOB : представляет массив бинарных данных, например, изображение, аналог типу int в java
Сохраняемые данные должны представлять соответствующие типы в java.
Создание и открытие базы данных
Для создания или открытия новой базы данных из кода Activity в Android мы можем вызвать метод openOrCreateDatabase() . Этот метод может принимать три параметра:
название для базы данных
числовое значение, которое определяет режим работы (как правило, в виде константы MODE_PRIVATE )
необязательный параметр в виде объекта SQLiteDatabase.CursorFactory , который представляет фабрику создания курсора для работы с бд
Например, создание базы данных app.db :
Для выполнения запроса к базе данных можно использовать метод execSQL класса SQLiteDatabase. В этот метод передается SQL-выражение. Например, создание в базе данных таблицы users:
Если нам надо не просто выполнить выражение, но и получить из бд какие-либо данные, то используется метод rawQuery() . Этот метод в качестве параметра принимает SQL-выражение, а также набор значений для выражения sql. Например, получение всех объектов из базы данных:
Метод db.rawQuery() возвращает объект Cursor, с помощью которого мы можем извлечь полученные данные.
Возможна ситуация, когда в базе данных не будет объектов, и для этого методом query.moveToFirst() пытаемся переместиться к первому объекту, полученному из бд. Если этот метод возвратит значение false, значит запрос не получил никаких данных из бд.
Теперь для работы с базой данных сделаем простейшее приложение. Для этого создадим новый проект.
В файле activity_main.xml определим простейший графический интерфейс:
А в классе MainActivity определим взаимодействие с базой данных:
По нажатию на кнопку здесь вначале создается в базе данных app.db новая таблица users, а затем в нее добавляются два объекта в базу данных с помощью SQL-выражения INSERT.
Далее с помощью выражения SELECT получаем всех добавленных пользователей из базы данных в виде курсора Cursor.
Вызовом query.moveToNext() перемещаемся в цикле while последовательно по всем объектам.
Для получения данных из курсора применяются методы query.getString(0) и query.getInt(1) . В скобках в методы передается номер столбца, из которого мы получаем данные. Например, выше мы добавили вначале имя пользователя в виде строки, а затем возраст в виде числа. Значит, нулевым столбцом будет идти строкое значение, которое получаем с помощью метода getString() , а следующим — первым столбцом идет числовое значение, для которого применяется метод getInt() .
После завершения работы с курсором и базой данных мы закрываем все связанные объекты:
Если мы не закроем курсор, то можем столкнуться с проблемой утечки памяти.
И если мы обратимся к приложению, то после нажатия на кнопку в текстовое поле будут выведены добавленные данные:
Android Studio: Fetch Data From Local Storage /SQLite(2020) in your app— PART 1 (Creating Database)
Let’s get started with using SQLite for your Android App. The whole tutorial will have two parts. For this part we are just focusing on creating a database with android studio.
For this I have created a simple project with simple design to get you started:
STEP 1: Designing the UI
Create a New Project in Android Studio and follow along.
In your project go to res>layout>activity_main.xml
Inside this file we will be creating some TextViews, EditText fields and some buttons. For this part we are only creating TextViews and EditText field for Product ID and Product Name and a Save Button. You can simply copy and paste the code below in your activity_main.xml file.
STEP 2: Creating DatabaseHelper Class
Now create a new package and name it database. Inside this package create a new class and name it DatabaseHelper.
Inside the DatabaseHelper class, we will have the code to create the database, create table , insert, update, delete and view methods.
At the beginning, we extend the DatabaseHelper class with SQLiteOpenHelper class. SQLiteOpenHelper class helps in the process of creating the database and managing version of the database.
After extending this class we will get some error message suggesting to implements some methods. Go ahead and implement all those methods.
This Creates two Methods onCreate() and onUpgrade(). This callbacks are invoked only when we try to open the database. onCreate() is for creating a database if it does not exists and onUpgrade() is for updating the database if the version is lower than requested by the constructor.
After this we are asked to create a constructor, let’s go ahead and do it. Select the first option.
Now, we are ready with a file with no errors.
Lets , now declare name of the database, name of the columns and version of the database along with some sql queries.
Now, lets make some changes in the constructor method. We will delete all other parameters and only keep the Context context. Change it to the following.
Now inside the onCreate() method, we pass the SQL_CREATE statement in execSQL() method. execSQL() helps you execute SQL queries.
And for the onUpgrade() method, we first delete the existing table and recreate it.
So the whole code in DatabaseHelper, looks like this:
STEP 3: Invoking DatabaseHelper constructor in MainActivity to create database.
STEP 4: Checking if the database is created or not.
Run the android project and check the data inside the Device File Explorer. Which is in the bottom right corner of android studio.
Click data>data> find your app (with package name)
In my case, my package is com.nirvik.localstorageapp and when I expand it I can see a database folder with database name I declared that is products.db.
In next part we will learn how to add , delete, update and view items inside the database from the app.
Android — SQLite Database
SQLite is a opensource SQL database that stores data to a text file on a device. Android comes in with built in SQLite database implementation.
SQLite supports all the relational database features. In order to access this database, you don’t need to establish any kind of connections for it like JDBC,ODBC e.t.c
Database — Package
The main package is android.database.sqlite that contains the classes to manage your own databases
Database — Creation
In order to create a database you just need to call this method openOrCreateDatabase with your database name and mode as a parameter. It returns an instance of SQLite database which you have to receive in your own object.Its syntax is given below
Apart from this , there are other functions available in the database package , that does this job. They are listed below
openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler)
This method only opens the existing database with the appropriate flag mode. The common flags mode could be OPEN_READWRITE OPEN_READONLY
openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags)
It is similar to the above method as it also opens the existing database but it does not define any handler to handle the errors of databases
openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory)
It not only opens but create the database if it not exists. This method is equivalent to openDatabase method.
openOrCreateDatabase(File file, SQLiteDatabase.CursorFactory factory)
This method is similar to above method but it takes the File object as a path rather then a string. It is equivalent to file.getPath()
Database — Insertion
we can create table or insert data into table using execSQL method defined in SQLiteDatabase class. Its syntax is given below
This will insert some values into our table in our database. Another method that also does the same job but take some additional parameter is given below
execSQL(String sql, Object[] bindArgs)
This method not only insert data , but also used to update or modify already existing data in database using bind arguments
Database — Fetching
We can retrieve anything from database using an object of the Cursor class. We will call a method of this class called rawQuery and it will return a resultset with the cursor pointing to the table. We can move the cursor forward and retrieve the data.
There are other functions available in the Cursor class that allows us to effectively retrieve the data. That includes
getColumnCount()
This method return the total number of columns of the table.
getColumnIndex(String columnName)
This method returns the index number of a column by specifying the name of the column
getColumnName(int columnIndex)
This method returns the name of the column by specifying the index of the column
getColumnNames()
This method returns the array of all the column names of the table.
This method returns the total number of rows in the cursor
getPosition()
This method returns the current position of the cursor in the table
This method returns true if the cursor is closed and return false otherwise
Database — Helper class
For managing all the operations related to the database , an helper class has been given and is called SQLiteOpenHelper. It automatically manages the creation and update of the database. Its syntax is given below
Example
Here is an example demonstrating the use of SQLite Database. It creates a basic contacts applications that allows insertion, deletion and modification of contacts.
To experiment with this example, you need to run this on an actual device on which camera is supported.
Steps | Description |
---|---|
1 | You will use Android studio to create an Android application under a package com.example.sairamkrishna.myapplication. |
2 | Modify src/MainActivity.java file to get references of all the XML components and populate the contacts on listView. |
3 | Create new src/DBHelper.java that will manage the database work |
4 | Create a new Activity as DisplayContact.java that will display the contact on the screen |
5 | Modify the res/layout/activity_main to add respective XML components |
6 | Modify the res/layout/activity_display_contact.xml to add respective XML components |
7 | Modify the res/values/string.xml to add necessary string components |
8 | Modify the res/menu/display_contact.xml to add necessary menu components |
9 | Create a new menu as res/menu/mainmenu.xml to add the insert contact option |
10 | Run the application and choose a running android device and install the application on it and verify the results. |
Following is the content of the modified MainActivity.java.
Following is the modified content of display contact activity DisplayContact.java
Following is the content of Database class DBHelper.java
Following is the content of the res/layout/activity_main.xml
Following is the content of the res/layout/activity_display_contact.xml
Following is the content of the res/value/string.xml
Following is the content of the res/menu/main_menu.xml
Following is the content of the res/menu/display_contact.xml
This is the defualt AndroidManifest.xml of this project
Let’s try to run your application. I assume you have connected your actual Android Mobile device with your computer. To run the app from Android studio , open one of your project’s activity files and click Run icon from the tool bar. Before starting your application,Android studio will display following window to select an option where you want to run your Android application.
Select your mobile device as an option and then check your mobile device which will display following screen −
Now open your optional menu, it will show as below image: Optional menu appears different places on different versions
Click on the add button of the menu screen to add a new contact. It will display the following screen −
It will display the following fields. Please enter the required information and click on save contact. It will bring you back to main screen.
SQLite на Android
SQLite доступен на любом Android-устройстве, его не нужно устанавливать отдельно.
SQLite поддерживает типы TEXT (аналог String в Java), INTEGER (аналог long в Java) и REAL (аналог double в Java). Остальные типы следует конвертировать, прежде чем сохранять в базе данных. SQLite сама по себе не проверяет типы данных, поэтому вы можете записать целое число в колонку, предназначенную для строк, и наоборот.
Вы не найдёте здесь тип, работающий с датами. Можно использовать строковые значения, например, как 2013-03-28 (28 марта 2013 года). Для даты со временем рекомендуется использовать формат 2013-03-27T07:58. В таких случаях можно использовать некоторые функции SQLite для добавления дней, установки начала месяца и т.д. Учтите, что SQLite не поддерживает часовые пояса.
Также не поддерживается тип boolean. Используйте числа 0 для false и 1 для true.
Не используйте тип BLOB для хранения данных (картинки) в Android. Лучше хранить в базе путь к изображениям, а сами изображения хранить в файловой системе.
Обратите внимание, что здесь не используется популярный в MySQL тип varchar(n), ограничивающий длину строки.
Всё, что вам нужно для начала работы с базой данных — задать необходимые настройки для создания или обновления базы данных.
Так как сама база данных SQLite представляет собой файл, то по сути при работе с базой данных, вы взаимодействуете с файлом. Поэтому операции чтения и записи могут быть довольно медленными. Настоятельно рекомендуется использовать асинхронные операции, например, при помощи класса AsyncTask.
Когда ваше приложение создаёт базу данных, она сохраняется в каталоге DATA/data/имя_пакета/databases/имя_базы.db.
Метод Environment.getDataDirectory() возвращает путь к каталогу DATA.
Основными пакетами для работы с базой данных являются android.database и android.database.sqlite.
База данных SQLite доступна только приложению, которое создаёт её. Если вы хотите дать доступ к данным другим приложениям, вы можете использовать контент-провайдеры (ContentProvider).
Запускаем SQLite на эмуляторе
С помощью утилиты ADB можно запустить SQLite на эмуляторе и работать с базами данных напрямую.
Напомню, что можно активировать команду sqlitе3 для одной из перечисленных баз данных, введя следующую команду:
Для завершения работы с sqlite3 напишите:
Обратите внимание: приглашение для adb — это #, а приглашение для sqlitе3 — это sqlite>.
Описание доступных команд sqlite3 есть на сайте: http://www.sqlite.org/sqlite.html. Перечислим некоторые важные команды.
Чтобы просмотреть список таблиц:
Быстрый доступ к главной таблице:
Таблица sqlite_master — это главная таблица (master table), в которой отслеживаются таблицы и виды, содержащиеся в базе данных. Следующая команда распечатывает инструкцию create для таблицы people, находящейся в базе данных contacts.db:
Это один из способов, позволяющих узнать названия всех столбцов, которые содержатся в таблице базы данных. Можно скопировать базу данных на локальный компьютер и изучать её в более комфортных условиях. Чтобы переместить файл contacts.db, можно дать следующую команду:
Классы для работы с SQLite
Работа с базой данных сводится к следующим задачам:
- Создание и открытие базы данных
- Создание таблицы
- Создание интерфейса для вставки данных (insert)
- Создание интерфейса для выполнения запросов (выборка данных)
- Закрытие базы данных
Класс ContentValues
Класс ContentValues используется для добавления новых строк в таблицу. Каждый объект этого класса представляет собой одну строку таблицы и выглядит как ассоциативный массив с именами столбцов и значениями, которые им соответствуют.
Курсоры
В Android запросы к базе данных возвращают объекты класса Cursor. Вместо того чтобы извлекать данные и возвращать копию значений, курсоры ссылаются на результирующий набор исходных данных. Курсоры позволяют управлять текущей позицией (строкой) в результирующем наборе данных, возвращаемом при запросе.
Класс SQLiteOpenHelper: Создание базы данных
Библиотека Android содержит абстрактный класс SQLiteOpenHelper, с помощью которого можно создавать, открывать и обновлять базы данных. Это основной класс, с которым вам придётся работать в своих проектах. При реализации этого вспомогательного класса от вас скрывается логика, на основе которой принимается решение о создании или обновлении базы данных перед ее открытием. Класс SQLiteOpenHelper содержит два обязательных абстрактных метода:
- onCreate() — вызывается при первом создании базы данных
- onUpgrade() — вызывается при модификации базы данных
Также используются другие методы класса:
- onDowngrade(SQLiteDatabase, int, int)
- onOpen(SQLiteDatabase)
- getReadableDatabase()
- getWritableDatabase()
В приложении необходимо создать собственный класс, наследуемый от SQLiteOpenHelper. В этом классе необходимо реализовать указанные обязательные методы, описав в них логику создания и модификации вашей базы.
В этом же классе принято объявлять открытые строковые константы для названия таблиц и полей создаваемой базы данных, которые клиенты могут использовать для определения столбцов при выполнении запросов к базе данных. Например, так можно объявить константы для таблицы CONTACT:
Лучше, если вы будете давать сразу понятные имена, указывающие на работу с таблицей. Если имя переменной TABLE_NAME ещё можно оставить, то для других лучше использовать более говорящие имена, например, KEY_NAME и KEY_PHONE или COLUMN_NAME, COLUMN_PHONE.
Ваш класс, расширяющий SQLiteOpenHelper, также неявно наследует интерфейс BaseColumns, в котором определена строковая константа _ID, представляющая имя поля для идентификаторов записей. В создаваемых таблицах базы данных поле _ID должно иметь тип INTEGER PRIMARY KEY AUTOINCREMENT. Описатель AUTOINCREMENT является необязательным. Часто в других примерах идентификатор создаётся вручную, смотрите как вам удобнее. Только всегда называйте его именно _id. Такое название используется в Android для работы с курсорами и поэтому придерживайтесь данного правила.
В методе onCreate() необходимо реализовать логику создания таблиц и при необходимости заполнить их начальными данными при помощи SQL-команды, например:
Здесь показана условная команда, в реальном коде вам нужно учитывать пробелы между константами, чтобы получилась правильная строка SQL-команды.
Также надо указать номер версии базы данных, начиная со значения 1. По этому номеру класс-обёртка будет понимать, что структуру базы данных следует обновить.
В методе onUpgrade() можно, например, реализовать запрос в базу данных на уничтожение таблицы (DROP TABLE), после чего вновь вызвать метод onCreate() для создания версии таблицы с обновленной структурой, например, так:
В параметрах метода используются номера версий базы данных — старая и новая. О номере версии говорилось выше.
Обновляется структура базы данных следующим образом. Сначала меняем порядковый номер.
При первой установке приложения базы данных ещё не существует. Тут проверять пока нечего. При установке новой версии приложения система проверит номер версии базы данных. Если он больше, чем было, то вызовется метод onUpgrade(). Если наоборот, то вызовется метод onDowngrade() (обычно так происходит редко).
Как использовать? Просто ставим условие на проверку.
Допустим, в таблицу нужно добавить новую колонку в дополнение к существующим колонкам NAME, DESCRIPTION и IMAGE_RESOURCE_ID. Для изменения таблицы используется выражение SQL с ключевым словом ALTER
Для замены имени таблицы используется выражение (меняем имя таблицы DOG на CAT):
Для удаления таблицы:
Соответственно, нужно вызвать метод SQLiteDatabase.execSQL(), передав ему нужную команду SQL.
Для удобства создадим вспомогательный метод updateDatabase().
Созданный метод теперь можно использовать в коде следующим образом.
Чтобы использовать реализацию вспомогательного класса, создайте новый экземпляр, передайте его конструктору контекст, имя базы данных, текущую версию и объект класса CursorFactory (если вы его используете). Вызовите метод getReadableDatabase() или getWritableDatabase(), чтобы открыть и вернуть экземпляр базы данных, с которой мы имеем дело (он будет доступен как для чтения, так и для записи). Вызов метода getWritableDatabase() может завершиться неудачно из-за проблем с полномочиями или нехваткой места на диске, поэтому лучше предусмотреть откат к методу getReadableDatabase().
Если база данных не существует, вспомогательный класс вызывает свой обработчик onCreate(); если версия базы данных изменилась, вызовется обработчик onUpgrade(). В любом случае вызов методов getWritableDatabase/getReadableDatabase, в зависимости от ситуации, вернет существующую, только что созданную или обновленную базу данных.
Оба метода имеют разные названия, но возвращают один и тот же объект. Только метод для чтения getReadableDatabase() сначала проверит доступность на чтение/запись. В случае ошибки метод проверит доступность на чтение и только потом уже вызовет исключение. Второй метод сразу проверяет доступ к чтению/записи и вызывает исключение при отказе в доступе.
Если вы планируете использовать несколько таблиц, то рекомендуется создавать для каждой таблицы отдельный класс.
SQLiteDatabase
Для управления базой данных SQLite существует класс SQLiteDatabase. В классе SQLiteDatabase определены методы query(), insert(), delete() и update() для чтения, добавления, удаления, изменения данных. Кроме того, метод execSQL() позволяет выполнять любой допустимый код на языке SQL применимо к таблицам базы данных, если вы хотите провести эти (или любые другие) операции вручную.
Каждый раз, когда вы редактируете очередное значение из базы данных, нужно вызывать метод refreshQuery() для всех курсоров, которые имеют отношение к редактируемой таблице.
Для составления запроса используются два метода: rawQuery() и query(), а также класс SQLiteQueryBuilder.
Метод query()
Для чтения данных используют вызов метода query():
В метод query() передают семь параметров. Если какой-то параметр для запроса вас не интересует, то оставляете null:
- table — имя таблицы, к которой передается запрос;
- String[] columnNames — список имен возвращаемых полей (массив). При передаче null возвращаются все столбцы;
- String whereClause — параметр, формирующий выражение WHERE (исключая сам оператор WHERE). Значение null возвращает все строки. Например: _id = 19 and summary = ?
- String[] selectionArgs — значения аргументов фильтра. Вы можете включить ? в «whereClause»». Подставляется в запрос из заданного массива;
- String[] groupBy — фильтр для группировки, формирующий выражение GROUP BY (исключая сам оператор GROUP BY). Если GROUP BY не нужен, передается null;
- String[] having — фильтр для группировки, формирующий выражение HAVING (исключая сам оператор HAVING). Если не нужен, передается null;
- String[] orderBy — параметр, формирующий выражение ORDER BY (исключая сам оператор ORDER BY). При сортировке по умолчанию передается null.
Объект Cursor, возвращаемый методом query(), обеспечивает доступ к набору записей результирующей выборки. Для обработки возвращаемых данных объект Cursor имеет набор методов для чтения каждого типа данных — getString(), getInt() и getFloat().
Чтобы получить все записи из нужных столбцов без условий, достаточно указать имя таблицы в первом параметре и строчный массив во втором. В остальных параметрах оставляем null:
Для запроса с условием используются третий и четвёртый параметр. Например, нам нужны записи, у которого имя кота будет Барсик:
Параметр «NAME = ?» означает, что столбец NAME должен содержать значение, указанное следующем параметре.
Множественные условия. Об этом говорилось выше.
Пример при использовании числовых значений, например, идентификатор первичного ключа (об этом тоже говорилось)
Для сортировки используется последний параметр. Нужно указать нужный столбец, по которому будет проводиться сортировка. По алфавиту с буквы A — ASC, наоборот — DESC
Возможна сортировка по нескольким столбцам.
Вы можете использовать функции SQL для составления запросов: AVG(), COUNT(), SUM(), MAX(), MIN() и др.
Ещё один абстрактный пример подсчёта средней суммы:
rawQuery()
Также существует метод rawQuery(), принимающий сырой SQL-запрос.
Метод rawQuery() — это сырой запрос, как есть, т.е. пишется строка запроса, как это обычно делается в SQL. Пример выглядит следующим образом:
Класс SQLiteQueryBuilder — удобный способ для построения запросов. Выбор за вами!
Метод insert()
Для вставки новой записи в базу данных SQLite используется метод insert():
В метод insert() необходимо передать три параметра:
- table — имя таблицы, в которую будет вставлена запись;
- nullColumnHack — в базе данных SQLite не разрешается вставлять полностью пустую строку, и если строка, полученная от клиента контент-провайдера, будет пустой, то только этому столбцу явно будет назначено значение null;
- values — карта отображений (класс Map и его наследники), передаваемая клиентом контент-провайдера, которая содержит пары ключ-значение. Ключи в карте должны быть названиями столбцов таблицы, значения — вставляемыми данными.
Метод insert() возвращает идентификатор _id вставленной строки или -1 в случае ошибки.
Для создания новой строки понадобится объект ContentValues, точнее, его метод put(), чтобы обеспечить данными каждый столбец. Объект ContentValues представляет собой пару name/value данных. Вставьте новую строку, передавая в метод insert(), вызванный в контексте нужной нам базы данных, имя таблицы и объект ContentValues
Метод update()
Для обновления и удаления записей в базе данных используют соответственно методы update() и delete():
В этих методах два последних параметра формируют SQL-выражение WHERE аналогично рассмотренному методу query() для чтения данных. Эти методы возвращают число модифицированных или удаленных строк.
Обновление строк также происходит с помощью класса ContentValues. Создайте новый объект ContentValues, используя метод put() для вставки значений в каждый столбец, который вы хотите обновить. Вызовите метод update() в контексте базы данных, передайте ему имя таблицы, обновленный объект ContentValues и оператор WHERE, указывающий на строку (строки), которую нужно обновить.
В первом параметре метода мы указываем имя таблицы, которую хотим обновить.
Во втором параметре мы указываем значение, которое хотим обновить. Например, в колонке «DESCRIPTION» нужно обновить значение на «Clever».
В третьем параметре указывается условие для обновления. Выражение «NAME = ?» означает, что колонка NAME должна быть равна указанному значению. Знак вопроса является подстановочным символом и из четвёртого параметра берётся нужное значение.
Обратите внимание, что последний параметр является массивом. Вы можете использовать множественные условия для запроса. Например, нам нужно обновить запись в таблице, используя сразу две колонки для составления условия.
Данный код соответствует выражению Where NAME = «Murzik» or DESCRIPTION = «Nice».
Для условий всегда используются строки, поэтому может понадобиться конвертация в некоторых случаях. Например, нужно использовать идентификатор таблицы со значением 1.
Если в последних двух параметрах использовать null, то будут обновлены все записи в таблице.
Метод delete()
Чтобы удалить строку, просто вызовите метод delete() в контексте базы данных, указав имя таблицы и оператор WHERE. В результате вы получите строки, которые хотите удалить:
Кроме вышеперечисленных методов, в этом классе также определены различные методы для выполнения других общих задач управления базой данных.
Метод openOrCreateDatabase: Открытие и создание баз данных без использования SQLiteOpenHelper
Вы можете открывать и создавать базы данных без помощи класса SQLiteOpenHelper, используя метод openOrCreateDatabase(), принадлежащий объекту Context вашего приложения. Получите доступ к базе данных в два шага. Сначала вызовите метод openOrCreateDatabase(), чтобы создать новую базу данных. Затем из полученного экземпляра базы данных вызовите execSQL(), чтобы выполнять команды на языке SQL, с помощью которых будут созданы таблицы и установлены отношения между ними.
Контент-провайдеры
Контент-провайдеры поддерживают стандартный синтаксис запросов для чтения, изменения, вставки и удаления данных. Если необходимо предоставить доступ к своим данных для других приложений, существует два варианта:
- создать собственный контент-провайдер, как подкласс класса ContentProvider;
- добавить данные к существующему провайдеру — если уже есть провайдер, который управляет теми же данными, и вы имеете разрешение для работы с этими данными.
Вставляем картинки в базу
Вставлять картинки в базу данных не самая лучшая идея. Оставлю только для ознакомления. Так как SQLite не работает с изображениями напрямую, то нужно сконвертировать картинку в байтовый массив. А при извлечении нужно проделать обратную задачу — из байтового массива воссоздать изображение. Создадим вспомогательный класс.
Создадим таблицу следующим образом. Переменная DATABASE_TABLE — строковая константа.
Урок 34. Хранение данных. SQLite
На прошлом уроке мы рассмотрели самый простой способ хранения данных — Preferences. Но способ этот достаточно ограничен и для хранения большого количества структурированных данных неудобен. На этом уроке рассмотрим SQLite. Это база данных с таблицами и запросами — все как в обычных БД.
Для начала, немного теории по взаимодействию приложения и БД.
В приложении, при подключении к БД мы указываем имя БД и версию. При этом могут возникнуть следующие ситуации:
1) БД не существует. Это может быть например в случае первичной установки программы. В этом случае приложение должно само создать БД и все таблицы в ней. И далее оно уже работает с только что созданной БД.
2) БД существует, но ее версия устарела. Это может быть в случае обновления программы. Например новой версии программы нужны дополнительные поля в старых таблицах или новые таблицы. В этом случае приложение должно апдейтить существующие таблицы и создать новые, если это необходимо.
3) БД существует и ее версия актуальна. В этом случае приложение успешно подключается к БД и работает.
Как вы понимаете, фраза «приложение должно» равнозначна фразе «разработчик должен», т.е. это наша задача. Для обработки описанных выше ситуаций нам надо создать класс, являющийся наследником для SQLiteOpenHelper. Назовем его DBHelper. Этот класс предоставит нам методы для создания или обновления БД в случаях ее отсутствия или устаревания.
onCreate — метод, который будет вызван, если БД, к которой мы хотим подключиться – не существует
onUpgrade — будет вызван в случае, если мы пытаемся подключиться к БД более новой версии, чем существующая
Давайте накидаем простое приложение – справочник контактов, которое будет хранить имя и email. Вводить данные будем на экране приложения, а для отображения информации используем логи. Обычно для этого используется List (список) – но мы эту тему пока не знаем. Да и не хочется перегружать приложение. Главное – освоить приемы работы с БД.
Project name: P0341_SimpleSQLite
Build Target: Android 2.3.3
Application name: SimpleSQLite
Package name: ru.startandroid.develop.p0341simplesqlite
Create Activity: MainActivity
Нарисуем экран для ввода записей и очистки таблицы. Открываем main.xml и пишем:
Пара полей для ввода и кнопки добавления записи, вывода существующих записей и очистки таблицы.
Открываем MainActivity.java и пишем:
Куча новых незнакомых слов в коде. Давайте разбираться.
В методе Activity — onCreate мы определяем объекты, присваиваем обработчики и создаем объект dbHelper класса DBHelper для управления БД. Сам класс будет описан ниже.
Далее смотрим метод Activity – onClick, в котором мы обрабатываем нажатия на кнопки.
Класс ContentValues используется для указания полей таблицы и значений, которые мы в эти поля будем вставлять. Мы создаем объект cv, и позже его используем. Далее мы записываем в переменные значения из полей ввода. Затем, с помощью метода getWritableDatabase подключаемся к БД и получаем объект SQLiteDatabase. Он позволит нам работать с БД. Мы будем использовать его методы insert – вставка записи, query – чтение, delete – удаление. У них много разных параметров на вход, но мы пока используем самый минимум.
Далее смотрим, какая кнопка была нажата:
btnAdd – добавление записи в таблицу mytable. Мы заполняем объект cv парами: имя поля и значение. И (при вставке записи в таблицу) в указанные поля будут вставлены соответствующие значения. Мы заполняем поля name и email. id у нас заполнится автоматически (primary key autoincrement). Вызываем метод insert – передаем ему имя таблицы и объект cv с вставляемыми значениями. Второй аргумент метода используется, при вставке в таблицу пустой строки. Нам это сейчас не нужно, поэтому передаем null. Метод insert возвращает ID вставленной строки, мы его сохраняем в rowID и выводим в лог.
btnRead – чтение всех записей из таблицы mytable. Для чтения используется метод query. На вход ему подается имя таблицы, список запрашиваемых полей, условия выборки, группировка, сортировка. Т.к. нам нужны все данные во всех полях без сортировок и группировок — мы используем везде null. Только имя таблицы указываем. Метод возвращает нам объект класса Cursor. Его можно рассматривать как таблицу с данными. Метод moveToFirst – делает первую запись в Cursor активной и заодно проверяет, есть ли вообще записи в нем (т.е. выбралось ли что-либо в методе query). Далее мы получаем порядковые номера столбцов в Cursor по их именам с помощью метода getColumnIndex. Эти номера потом используем для чтения данных в методах getInt и getString и выводим данные в лог. С помощью метода moveToNext мы перебираем все строки в Cursor пока не добираемся до последней. Если же записей не было, то выводим в лог соответствующее сообщение – 0 rows. В конце закрываем курсор (освобождаем занимаемые им ресурсы) методом close, т.к. далее мы его нигде не используем.
btnClear – очистка таблицы. Метод delete удаляет записи. На вход передаем имя таблицы и null в качестве условий для удаления, а значит удалится все. Метод возвращает кол-во удаленных записей.
После этого закрываем соединение с БД методом close.
Класс DBHelper является вложенным в MainActivity и описан в конце кода. Как я уже писал выше, этот класс должен наследовать класс SQLiteOpenHelper.
В конструкторе мы вызываем конструктор суперкласса и передаем ему:
context — контекст
mydb — название базы данных
null – объект для работы с курсорами, нам пока не нужен, поэтому null
1 – версия базы данных
В методе onCreate этого класса мы используем метод execSQL объекта SQLiteDatabase для выполнения SQL-запроса, который создает таблицу. Напомню – этот метод вызывается, если БД не существует и ее надо создавать. По запросу видно, что мы создаем таблицу mytable с полями id, name и email.
Метод onUpgrade пока не заполняем, т.к. используем одну версию БД и менять ее не планируем.
Все сохраним и запустим приложение. Будем работать с БД и смотреть логи, которые покажут, какие методы выполняются, и что в них происходит.
Введем чего-нить в поля ввода и нажмем Add.
— onCreate database —
— Insert in mytable: —
row inserted, >
Мы видим, что вызывался метод onCreate в классе DBHelper, а значит выполнялся скрипт по созданию таблицы. Это произошло потому, что это первый запуск приложения и БД еще не была создана. Теперь БД существует и с ней можно работать.
Далее видим, что вызывался метод вставки записи и вернул ID = 1.
Вставим еще какую-нибудь запись.
— Insert in mytable: —
row inserted, >
На этот раз onCreate не вызывался, т.к. БД уже существует. Вставилась запись с >
Давайте посмотрим содержимое таблицы — нажмем кнопку Read и посмотрим лог:
— Rows in mytable: —
name = John Smith, email = Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
name = Some body, email = Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
Мы видим записи, которые вставляли. Тут все верно.
Теперь очистим таблицу — нажмем Clear. Смотрим лог:
— Clear mytable: —
deleted rows count = 2
Удалено две записи, все верно. Если теперь посмотрим содержимое таблицы – кнопка Read:
— Rows in mytable: —
0 rows
В этой теме важно понять, что для работы с БД мы использовали два класса:
— DBHelper, наследующий SQLiteOpenHelper. В его конструкторе мы вызываем конструктор супер-класса и указываем имя и версию БД. Метод getWritableDatabase выполняет подключение к базе данных и возвращает нам объект SQLiteDatabase для работы с ней. Метод close закрывает подключение к БД. В случае, когда БД отсутствует или устарела, класс предоставляет нам самим реализовать создание или обновление в методах onCreate и onUpgrate.
— SQLiteDatabase. Содержит методы для работы с данными – т.е. вставка, обновление, удаление и чтение.
Файл базы можно найти в File Explorer, как и на прошлом уроке. Путь к нему data/data/ru.startandroid.develop.p0341simpelsqlite/databases/myDB.
На следующем уроке продолжим это приложение. Добавим возможность обновления и удаления конкретных записей.
Важное замечание
Я в своих примерах выполняю все операции с базой данных в основном потоке. Я делаю так, чтобы не усложнять урок. Но в реале вам следует использовать для работы с БД отдельный поток, чтобы ваше приложение не тормозило визуально. О том, как это сделать, я пишу в уроках 80-91 и 135-136.
На следующем уроке:
— используем методы query и delete с указанием условия
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
Android Studio: Fetch Data From Local Storage /SQLite(2020) in your app— PART 1 (Creating Database)
Let’s get started with using SQLite for your Android App. The whole tutorial will have two parts. For this part we are just focusing on creating a database with android studio.
For this I have created a simple project with simple design to get you started:
STEP 1: Designing the UI
Create a New Project in Android Studio and follow along.
In your project go to res>layout>activity_main.xml
Inside this file we will be creating some TextViews, EditText fields and some buttons. For this part we are only creating TextViews and EditText field for Product ID and Product Name and a Save Button. You can simply copy and paste the code below in your activity_main.xml file.
STEP 2: Creating DatabaseHelper Class
Now create a new package and name it database. Inside this package create a new class and name it DatabaseHelper.
Inside the DatabaseHelper class, we will have the code to create the database, create table , insert, update, delete and view methods.
At the beginning, we extend the DatabaseHelper class with SQLiteOpenHelper class. SQLiteOpenHelper class helps in the process of creating the database and managing version of the database.
After extending this class we will get some error message suggesting to implements some methods. Go ahead and implement all those methods.
This Creates two Methods onCreate() and onUpgrade(). This callbacks are invoked only when we try to open the database. onCreate() is for creating a database if it does not exists and onUpgrade() is for updating the database if the version is lower than requested by the constructor.
After this we are asked to create a constructor, let’s go ahead and do it. Select the first option.
Now, we are ready with a file with no errors.
Lets , now declare name of the database, name of the columns and version of the database along with some sql queries.
Now, lets make some changes in the constructor method. We will delete all other parameters and only keep the Context context. Change it to the following.
Now inside the onCreate() method, we pass the SQL_CREATE statement in execSQL() method. execSQL() helps you execute SQL queries.
And for the onUpgrade() method, we first delete the existing table and recreate it.
So the whole code in DatabaseHelper, looks like this:
STEP 3: Invoking DatabaseHelper constructor in MainActivity to create database.
STEP 4: Checking if the database is created or not.
Run the android project and check the data inside the Device File Explorer. Which is in the bottom right corner of android studio.
Click data>data> find your app (with package name)
In my case, my package is com.nirvik.localstorageapp and when I expand it I can see a database folder with database name I declared that is products.db.
In next part we will learn how to add , delete, update and view items inside the database from the app.
SQLiteDatabase
SQLiteDatabase has methods to create, delete, execute SQL commands, and perform other common database management tasks.
See the Notepad sample application in the SDK for an example of creating and managing a database.
Database names must be unique within an application, not across all applications.
Localized Collation — ORDER BY
In addition to SQLite’s default BINARY collator, Android supplies two more, LOCALIZED , which changes with the system’s current locale, and UNICODE , which is the Unicode Collation Algorithm and not tailored to the current locale.
Summary
Nested Classes | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
SQLiteDatabase.CursorFactory | Used to allow returning sub-classes of Cursor when calling query. |
Constants | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
int | CONFLICT_ABORT | When a constraint violation occurs,no ROLLBACK is executed so changes from prior commands within the same transaction are preserved. | |||||||||
int | CONFLICT_FAIL | When a constraint violation occurs, the command aborts with a return code SQLITE_CONSTRAINT. | |||||||||
int | CONFLICT_IGNORE | When a constraint violation occurs, the one row that contains the constraint violation is not inserted or changed. | |||||||||
int | CONFLICT_NONE | Use the following when no conflict action is specified. | |||||||||
int | CONFLICT_REPLACE | When a UNIQUE constraint violation occurs, the pre-existing rows that are causing the constraint violation are removed prior to inserting or updating the current row. | |||||||||
int | CONFLICT_ROLLBACK | When a constraint violation occurs, an immediate ROLLBACK occurs, thus ending the current transaction, and the command aborts with a return code of SQLITE_CONSTRAINT. | |||||||||
int | CREATE_IF_NECESSARY | Open flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to create the database file if it does not already exist. | |||||||||
int | ENABLE_WRITE_AHEAD_LOGGING | Open flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database file with write-ahead logging enabled by default. | |||||||||
int | MAX_SQL_CACHE_SIZE | Absolute max value that can be set by setMaxSqlCacheSize(int) . | |||||||||
int | NO_LOCALIZED_COLLATORS | Open flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database without support for localized collators. | |||||||||
int | OPEN_READONLY | Open flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database for reading only. | |||||||||
int | OPEN_READWRITE | Open flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database for reading and writing. If the disk is full, this may fail even before you actually write anything. | |||||||||
int | SQLITE_MAX_LIKE_PATTERN_LENGTH | Maximum Length Of A LIKE Or GLOB Pattern The pattern matching algorithm used in the default LIKE and GLOB implementation of SQLite can exhibit O(N^2) performance (where N is the number of characters in the pattern) for certain pathological cases. |
Public Methods | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Constantspublic static final int CONFLICT_ABORTWhen a constraint violation occurs,no ROLLBACK is executed so changes from prior commands within the same transaction are preserved. This is the default behavior. public static final int CONFLICT_FAILWhen a constraint violation occurs, the command aborts with a return code SQLITE_CONSTRAINT. But any changes to the database that the command made prior to encountering the constraint violation are preserved and are not backed out. public static final int CONFLICT_IGNOREWhen a constraint violation occurs, the one row that contains the constraint violation is not inserted or changed. But the command continues executing normally. Other rows before and after the row that contained the constraint violation continue to be inserted or updated normally. No error is returned. public static final int CONFLICT_NONEUse the following when no conflict action is specified. public static final int CONFLICT_REPLACEWhen a UNIQUE constraint violation occurs, the pre-existing rows that are causing the constraint violation are removed prior to inserting or updating the current row. Thus the insert or update always occurs. The command continues executing normally. No error is returned. If a NOT NULL constraint violation occurs, the NULL value is replaced by the default value for that column. If the column has no default value, then the ABORT algorithm is used. If a CHECK constraint violation occurs then the IGNORE algorithm is used. When this conflict resolution strategy deletes rows in order to satisfy a constraint, it does not invoke delete triggers on those rows. This behavior might change in a future release. public static final int CONFLICT_ROLLBACKWhen a constraint violation occurs, an immediate ROLLBACK occurs, thus ending the current transaction, and the command aborts with a return code of SQLITE_CONSTRAINT. If no transaction is active (other than the implied transaction that is created on every command) then this algorithm works the same as ABORT. public static final int CREATE_IF_NECESSARYOpen flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to create the database file if it does not already exist. public static final int ENABLE_WRITE_AHEAD_LOGGINGOpen flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database file with write-ahead logging enabled by default. Using this flag is more efficient than calling enableWriteAheadLogging() . Write-ahead logging cannot be used with read-only databases so the value of this flag is ignored if the database is opened read-only. See Alsopublic static final int MAX_SQL_CACHE_SIZEAbsolute max value that can be set by setMaxSqlCacheSize(int) . Each prepared-statement is between 1K — 6K, depending on the complexity of the SQL statement & schema. A large SQL cache may use a significant amount of memory. public static final int NO_LOCALIZED_COLLATORSOpen flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database without support for localized collators. This causes the collator LOCALIZED not to be created. You must be consistent when using this flag to use the setting the database was created with. If this is set, setLocale(Locale) will do nothing. public static final int OPEN_READONLYOpen flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database for reading only. This is the only reliable way to open a database if the disk may be full. public static final int OPEN_READWRITEOpen flag: Flag for openDatabase(String, SQLiteDatabase.CursorFactory, int) to open the database for reading and writing. If the disk is full, this may fail even before you actually write anything. Note that the value of this flag is 0, so it is the default. public static final int SQLITE_MAX_LIKE_PATTERN_LENGTHMaximum Length Of A LIKE Or GLOB Pattern The pattern matching algorithm used in the default LIKE and GLOB implementation of SQLite can exhibit O(N^2) performance (where N is the number of characters in the pattern) for certain pathological cases. To avoid denial-of-service attacks the length of the LIKE or GLOB pattern is limited to SQLITE_MAX_LIKE_PATTERN_LENGTH bytes. The default value of this limit is 50000. A modern workstation can evaluate even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly. The denial of service problem only comes into play when the pattern length gets into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns are at most a few dozen bytes in length, paranoid application developers may want to reduce this parameter to something in the range of a few hundred if they know that external users are able to generate arbitrary patterns. Public Methodspublic void beginTransaction ()Begins a transaction in EXCLUSIVE mode. Transactions can be nested. When the outer transaction is ended all of the work done in that transaction and all of the nested transactions will be committed or rolled back. The changes will be rolled back if any transaction is ended without being marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. Here is the standard idiom for transactions: public void beginTransactionNonExclusive ()Begins a transaction in IMMEDIATE mode. Transactions can be nested. When the outer transaction is ended all of the work done in that transaction and all of the nested transactions will be committed or rolled back. The changes will be rolled back if any transaction is ended without being marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. Here is the standard idiom for transactions: public void beginTransactionWithListener (SQLiteTransactionListener transactionListener)Begins a transaction in EXCLUSIVE mode. Transactions can be nested. When the outer transaction is ended all of the work done in that transaction and all of the nested transactions will be committed or rolled back. The changes will be rolled back if any transaction is ended without being marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. Here is the standard idiom for transactions: Parameterspublic void beginTransactionWithListenerNonExclusive (SQLiteTransactionListener transactionListener)Begins a transaction in IMMEDIATE mode. Transactions can be nested. When the outer transaction is ended all of the work done in that transaction and all of the nested transactions will be committed or rolled back. The changes will be rolled back if any transaction is ended without being marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed. Here is the standard idiom for transactions: Parameterspublic SQLiteStatement compileStatement (String sql)Compiles an SQL statement into a reusable pre-compiled statement object. The parameters are identical to execSQL(String) . You may put ?s in the statement and fill in those values with bindString(int, String) and bindLong(int, long) each time you want to run the statement. Statements may not return result sets larger than 1×1. No two threads should be using the same SQLiteStatement at the same time. ParametersReturns
Throwspublic static SQLiteDatabase create (SQLiteDatabase.CursorFactory factory)Create a memory backed SQLite database. Its contents will be destroyed when the database is closed. Sets the locale of the database to the the system’s current locale. Call setLocale(Locale) if you would like something else. ParametersReturns
public int delete (String table, String whereClause, String[] whereArgs)Convenience method for deleting rows in the database. ParametersReturns
public static boolean deleteDatabase (File file)Deletes a database including its journal file and other auxiliary files that may have been created by the database engine. ParametersReturns
public void disableWriteAheadLogging ()This method disables the features enabled by enableWriteAheadLogging() . ThrowsSee Alsopublic boolean enableWriteAheadLogging ()This method enables parallel execution of queries from multiple threads on the same database. It does this by opening multiple connections to the database and using a different database connection for each query. The database journal mode is also changed to enable writes to proceed concurrently with reads. When write-ahead logging is not enabled (the default), it is not possible for reads and writes to occur on the database at the same time. Before modifying the database, the writer implicitly acquires an exclusive lock on the database which prevents readers from accessing the database until the write is completed. In contrast, when write-ahead logging is enabled (by calling this method), write operations occur in a separate log file which allows reads to proceed concurrently. While a write is in progress, readers on other threads will perceive the state of the database as it was before the write began. When the write completes, readers on other threads will then perceive the new state of the database. It is a good idea to enable write-ahead logging whenever a database will be concurrently accessed and modified by multiple threads at the same time. However, write-ahead logging uses significantly more memory than ordinary journaling because there are multiple connections to the same database. So if a database will only be used by a single thread, or if optimizing concurrency is not very important, then write-ahead logging should be disabled. After calling this method, execution of queries in parallel is enabled as long as the database remains open. To disable execution of queries in parallel, either call disableWriteAheadLogging() or close the database and reopen it. The maximum number of connections used to execute queries in parallel is dependent upon the device memory and possibly other properties. If a query is part of a transaction, then it is executed on the same database handle the transaction was begun. Writers should use beginTransactionNonExclusive() or beginTransactionWithListenerNonExclusive(SQLiteTransactionListener) to start a transaction. Non-exclusive mode allows database file to be in readable by other threads executing queries. If the database has any attached databases, then execution of queries in parallel is NOT possible. Likewise, write-ahead logging is not supported for read-only databases or memory databases. In such cases, enableWriteAheadLogging() returns false. The best way to enable write-ahead logging is to pass the ENABLE_WRITE_AHEAD_LOGGING flag to openDatabase(String, SQLiteDatabase.CursorFactory, int) . This is more efficient than calling enableWriteAheadLogging() . Another way to enable write-ahead logging is to call enableWriteAheadLogging() after opening the database. See also SQLite Write-Ahead Logging for more details about how write-ahead logging works. Реализация доступа к базам данных в среде DELPHIКомпонент типа TQuery позволяет выполнять любой SQL-оператор, допустимый по синтаксису ODBC-драйвером. Если в качестве выполнимого оператора используется SQL-оператор SELECT , то компонент возвращает набор данных (результирующий набор). В отличие от класса Ttable , класс TQuery позволяет создавать наборы данных из нескольких таблиц, а также ограничивать получаемый набор данных определенными условиями. Это отменяет необходимость извлечения всех записей таблицы в набор данных, что, в свою очередь, экономит память, сокращает сетевой трафик для удаленных баз данных и уменьшает время доступа. Для определения набора данных TQuery следует установить значение свойства SQL и, возможно, свойства DatabaseName (свойство DatabaseName определяет имя источника данных, но для некоторых баз данных можно задать полное имя таблицы, включающее месторасположение файла, в тексте SQL-оператора, — в этом случае свойство DatabaseName не используется). Наиболее правильным подходом все же следует считать тот, при котором имя DSN источника данных указывается свойством DatabaseName , а в SQL-операторе определяется только имя таблицы без определения ее местоположения. По умолчанию, набор данных, формируемый компонентом типа TQuery , не является редактируемым. Для того чтобы значения в созданном наборе данных можно было редактировать, необходимо выполнить одно из следующих действий:
Класс TQuery содержит свойства и методы, используемые для работы с набором данных, включая следующие: DataSource — свойство, позволяющее указать родительский набор данных (для отношения «родительский-дочерний»). Например, если свойство SQL содержит значение ‘SELECT * FROM Tbl1 t WHERE (t.FNo = :FNo)’ , то значение переменной связи :FNo будет определяться из источника данных, указанного свойством DataSource . Params — свойство, содержащее список параметров для SQL-оператора. ExecSQL — метод, выполняющий SQL-оператор, указанный свойством SQL (для SQL-оператора, создающего набор данных, вместо ExecSQL используется метод Open ). ExecSQL можно вызывать для таких SQL-операторов как INSERT , UPDATE , DELETE , CREATE TABLE и т. п. Если перед вызовом ExecSQL не был вызван метод Prepare , то SQL-оператор будет одновременно и откомпилирован, и выполнен. Prepare — метод, выполняющий компиляцию SQL-оператора. Вызов этого метода перед ExecSQL увеличивает скорость выполнения запроса при многократном повторении вызовов ExecSQL для одного и того же оператора (например, параметризированного запроса). Это позволяет откомпилировать SQL-оператор только один раз, а затем многократно его выполнять. |