DB SQLite Implementation Tools
DB SQLite Implementation Tools
Implementation Tools
Edwin Sundberg [email protected]
Melle Carnesten [email protected]
1
Contents
1 The Database Model 4
3 SQLite in General 6
3.1 Datatypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Date and Time Management . . . . . . . . . . . . . . . . . . 6
3.2.1 Handling Dates Correctly . . . . . . . . . . . . . . . . 7
3.2.2 Anti-examples of Date and Time Management . . . . 8
4 DBeaver Community 9
4.1 Relevant Known Issues . . . . . . . . . . . . . . . . . . . . . 9
4.1.1 Bad Primary Key due to auto increment . . . . . . . . 9
4.2 Common Problems . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2.1 Foreign Key Constraints are not enforced . . . . . . . 9
4.2.2 ERD Created Foreign Key Constraints . . . . . . . . . 11
4.2.3 Editing a Column . . . . . . . . . . . . . . . . . . . . . 11
4.3 Creating Databases . . . . . . . . . . . . . . . . . . . . . . . 11
4.4 Creating Tables . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4.1 User Table . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4.2 MailAddress Table . . . . . . . . . . . . . . . . . . . . 14
4.4.3 MailGoesTo Table . . . . . . . . . . . . . . . . . . . . 15
4.5 Alternative Keys . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.6 Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.6.1 MailAddress → User . . . . . . . . . . . . . . . . . . . 20
4.6.2 MailGoesTo → MailAddress . . . . . . . . . . . . . . . 20
4.7 Inserting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.8 Querying Data . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5 SQLiteStudio 24
5.1 Relevant Known Issues . . . . . . . . . . . . . . . . . . . . . 24
5.1.1 Creating self-referencing foreign keys . . . . . . . . . 24
5.2 Common Problems . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2.1 Table Missing . . . . . . . . . . . . . . . . . . . . . . . 25
5.2.2 No Primary Key . . . . . . . . . . . . . . . . . . . . . . 25
5.2.3 Wrong Datatype for Foreign Key . . . . . . . . . . . . 26
5.3 Creating a Database . . . . . . . . . . . . . . . . . . . . . . . 27
5.4 Creating a Table . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.4.1 User Table . . . . . . . . . . . . . . . . . . . . . . . . 30
5.4.2 MailAddress Table . . . . . . . . . . . . . . . . . . . . 31
5.4.3 MailGoesTo Table . . . . . . . . . . . . . . . . . . . . 33
5.5 Alternative Keys . . . . . . . . . . . . . . . . . . . . . . . . . 34
2
5.6 Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.7 Inserting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.8 Querying Data . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6 SQLite ERD 43
7 Final Words 44
3
1 The Database Model
In this document we will be using a simple database model which rep-
resents an email system, where users are able to create multiple recip-
ient addresses and receive all incoming emails to one or more inboxes.
All inboxes can be shared with other users in the system and receiv-
ing email may optionally be encrypted with a provided public key (see
https://en.wikipedia.org/wiki/Public-key_cryptography).
The original domain correct UML class diagram can be seen in figure
Figure 1. And the corresponding database model can be seen in figure Fig-
ure 2. This document will not go into details on how or why the database
model is created this way but rather focus on how to use the SQLite Mod-
elling Tools to implement the database model. For details on how to go
to a RDBMS friendly model from a domain model see lecture slides and
literature.
Figure 1: The original UML class diagram for the email system.
4
Figure 2: The database model for the email system.
5
2 The SQLite Implementation Tools
The following tools will be presented in this document:
3 SQLite in General
3.1 Datatypes
Typing is not strict in SQLite, but we recommend to stick to the following
datatypes for the database model:
• INTEGER
• TEXT
• REAL
While typing is not strict it is still highly recommended to insert data of the
correct type to avoid logical errors, i.e. only insert integers into INTEGER
columns and no strings into INTEGER columns. Note: SQLite ERD (see
section 6) will throw semantic errors if there exists data of the “wrong” type
in a column.
6
3.2.1 Handling Dates Correctly
There are a few approaches to handle dates correctly in SQLite, the fol-
lowing are some examples of querying all “inboxes” that have been created
during the year 2025:
1 SELECT
2 *
3 FROM
4 inboxes
5 WHERE
6 createdAt BETWEEN ' 2025 -01 -01 ' AND ' 2025 -12 -31 ' ;
SQL 1: Querying using BETWEEN
1 SELECT
2 *
3 FROM
4 inboxes
5 WHERE
6 -- The strftime function extracts the year (% Y ) from
7 -- the ' createdAt ' column .
8 -- It returns the year as a text
9 -- string ( e . g . , ' 2025 ' ).
10 CAST (
11 strftime ( ' % Y ' , createdAt )
12 AS INT -- The CAST converts the year string to
13 -- an integer for numeric comparison .
14 ) = 2025;
SQL 2: Querying using strftime
The solutions presented above will work independently of the format the
date is stored in the database (i.e. TEXT, INTEGER, REAL) assuming the
datatype matches the format as explained in subsection 3.2.
7
3.2.2 Anti-examples of Date and Time Management
The following are anti-examples of how to not handle dates in SQLite. The
following examples may produce unexpected results and should be avoided
as they handle the date as a string and not as a date and will completely
break if Unix Time or Julian Day Number is used (or switched to) as the
storage format.
1 SELECT
2 *
3 FROM
4 inboxes
5 WHERE
6 -- Matches all strings starting with
7 -- ' 2025 ' ( e . g . ' 2025 HELLO ' ).
8 createdAt LIKE ' 2025% ' ;
SQL 4: Anti-example of date querying using LIKE
1 SELECT
2 *
3 FROM
4 inboxes
5 WHERE
6 -- Matches all strings starting with
7 -- ' 2025 ' ( e . g . ' 2025 HELLO ' ).
8 createdAt >= ' 2025 ' ;
9 OR
10 -- Is internally casted to the same as above .
11 createdAt >= 2025;
SQL 5: Anti-example of date querying using >=
1 SELECT
2 *
3 FROM
4 inboxes
5 WHERE
6 -- This will return an undefined result set since
7 -- DD / MM / YYYY is not ISO -8601 format .
8 createdAt BETWEEN ' 01/01/2025 ' AND ' 12/31/2025 ' ;
SQL 6: Anti-example of date querying with incorrect BETWEEN
8
4 DBeaver Community
4.1 Relevant Known Issues
4.1.1 Bad Primary Key due to auto increment
When creating an integer column in DBeaver Community with the “auto in-
crement” box checked the SQL generated will have a PK constraint created
twice. This will result in an error when trying to persist the changes since
a table can only have one PRIMARY KEY constraint. The following code is
generated by DBeaver Community when trying to persist the changes:
1 CREATE TABLE BadPK (
2 Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT ,
3 CONSTRAINT BadPK_PK PRIMARY KEY ( Column1 )
4 );
SQL 7: Bad Primary Key due to auto increment in DBeaver
The solution to this is to never use the “auto increment box” (for a SQLite
database in DBeaver) when creating a PK in the program. Unchecking the
box will instead yield the following code:
1 CREATE TABLE GoodPK (
2 Column1 INTEGER NOT NULL ,
3 CONSTRAINT GoodPK_PK PRIMARY KEY ( Column1 )
4 );
SQL 8: Ok Primary Key in DBeaver if auto increment is unchecked
DBeaver does not enforce foreign key constraints by default. This can ei-
ther be enabled when creating a new database (see subsection 4.3) or by
editing the database connection settings as follows:
9
Figure 4: Edit Connection in DBeaver.
10
4.2.2 ERD Created Foreign Key Constraints
3. Choose a file location for the database with “Create...” ensure to name
the file with the extension “.db3” or “.sqlite3” (Figure 9).
5. Press “Finish”.
11
Figure 8: New SQLite Database in DBeaver.
12
Figure 10: Enable Foreign Keys in DBeaver.
13
4.4 Creating Tables
From the database model, we will be implementing the User and the
MailAddress tables. The rest of the tables can be implemented similarly
and is left as an exercise for the reader.
2. Fill out the Table Name field, navigate to the “Columns” tab, right click
and choose “Add Column” (Figure 12).
3. Add the column for username, set the datatype to “TEXT”, check the
box for “NOT NULL” and the box for “Unique” in order to create a
single column primary key (Figure 13).
5. Save with “Ctrl + S” (or your operating system’s equivalent) and press
“Execute”.
The process for creating the MailAddress table is similar to the User table
with the exception that the primary key is a composite key. The PK for the
table consists of the columns “username” and “domain”. Steps for creating
columns are the same as for 4.4.1, creating the composite key is done as
follows:
14
Figure 12: Add Column in DBeaver.
3. Set the type to “Primary Key” and tick the columns “username” and
“domain” to the key (Figure 16).
The process of creating the MailGoesTo table is almost identical to the sub-
subsection 4.4.2 with the exception that all columns are part of the primary
key. The resulting table can be visualized with DBeaver as Figure 18.
15
Figure 14: User ER Diagram in DBeaver.
16
Figure 16: MailAddress Primary Key in DBeaver.
17
Figure 18: MailGoesTo ER Diagram in DBeaver.
18
4.5 Alternative Keys
To create an alternative key (unique index) in DBeaver this can be exempli-
fied on User by declaring that the columns “fullName” and “phoneNumber”
should be unique together. This can be done as follows:
3. Select the columns “fullName” and “phoneNumber”, tick the box for
“Unique” and press “OK”. (Figure 20)
19
4.6 Foreign Keys
Creating foreign keys in DBeaver will be exemplified on the relation-
ships between MailAddress.(createdBy) → User.(username) and Mail-
GoesTo.(username, domain) → MailAddress.(username, domain).
20
Figure 22: Create Foreign Key MailAddress → User in DBeaver.
21
Figure 23: Create Foreign Key MailGoesTo → MailAddress in DBeaver.
22
Figure 24: Insert Data into User in DBeaver.
23
And the process for doing this in DBeaver is as follows:
1. Right-click on “Views” and choose “Create New View”. (Figure 26)
2. Give the view a name and navigate to definition and write the query.
(Figure 27)
4. Navigate to the “Data” tab of the view to see the result. (Figure 28)
5 SQLiteStudio
5.1 Relevant Known Issues
5.1.1 Creating self-referencing foreign keys
24
have to create the table without the foreign key first. After that, you can go
to the table and add the foreign key.
If the table structure is not properly created/committed before attempt-
ing to add the foreign key the target table will not be available in the drop-
down list of tables to reference. See Figure 29 for an example of this.
Figure 29: The table is not available in the dropdown list of tables to refer-
ence.
SQLiteStudio has each table in its own tab, if you accidentally go to a new
table and your old one disappeared from your current view. Check the tabs
at the bottom of the screen.
25
Figure 30: Table in different window in SQLiteStudio.
keys). This is not an error, but all tables should have an explicit primary key
defined.
26
Figure 31: Wrong Datatype for Foreign Key Column in SQLiteStudio.
27
Figure 32: Popup for creating a new database in SQLiteStudio.
Figure 33: Example for how to select the folder you want to store your
database in.
28
Figure 34: How the popup should look when entered everything.
29
5.4 Creating a Table
To create a table in SQLiteStudio star by clicking in your database to get
tables and views. Then right-click on the tables and selected create new
table. Figure 35
Figure 35: The dropout menu for creating a new table in SQLiteStudio.
In this section we will create the User table and the MailAddress table.
The rest of the tables can be created similarly, and are as such left as
an exercise for the reader. We will only cover the creation of the primary
keys of User and MailAddress Tables because the rest of the columns are
created similarly, with the difference that you don’t mark them as primary
keys.
After selecting create new table you will be presented with a blank table,
see Figure 36 you start by entering the name, this is going to be the user
table. At the top of the user table all options will be greyed out except for
Figure 36: The dropout menu for creating a new table in SQLiteStudio.
“commit structure changes” and “add column”. Press add column. You
will be presented with the window to create a column, Figure 37. The first
column we will create is the username column. The name of the column
30
Figure 37: Blank menu for creating a new column in SQLiteStudio.
is username and then select the datatype from the list next to the name
of the column. We will make it the primary key and set it to NOT NULL
by checking the boxes, Figure 38. Now you can press “Commit structure
changes” to save the table. Then you will get a window with a SQL query
that will be executed to create the table, you don’t need to do anything here
just press OK.
You can repeat the steps from adding the username column to add the
fullName and phoneNumber columns.
MailAddress table is created in the same way as the User table. The only
difference is that the primary key is a composite key. It is both the username
and domain columns. We will start with the same steps and creating a new
table as we did with the User table. After that we will add the username
and domain columns, checking both as NOT NULL but importantly not as a
primary key! The table should look like Figure 39.
In the items on the bottom of the table view you can see a key icon,
press this button, Figure 40. You will be presented with a window where you
can select the columns that should be part of the primary key, Figure 40.
Select the username and domain columns. You can and should (for now)
ignore the rest of the options in the window. Press create and then press
31
Figure 38: Filled menu for creating a new column in SQLiteStudio.
Figure 39: Created two columns in MailAddress table which are not primary
keys.
“Commit structure changes” to save the table. After that you can create
the rest of the columns in the same way as you did with the User table. If
you got a key eye for UML diagrams you can see that username will be a
foreign key in MailAddress table, foreign keys will be covered later under
the chapter Foreign Keys.
32
Figure 40: Menu for adding primary keys in MailAddress table.
33
5.5 Alternative Keys
To create an alternative key in SQLiteStudio you press the button with three
colored squares, Figure 42. After which you will be presented with a win-
dow where you can select the columns that should be part of the alterna-
tive key, Figure 43. To demonstrate we will create a composite key of the
columns fullName and phoneNumber in the User table. After selecting the
columns you can press the key icon to create the key. You can see that the
alternative is created in the area below the table view, Figure 44.
34
Figure 44: Table view for user table with the alternative key.
Figure 45: View over MailAddress table with the button for creating a foreign
key.
(Figure 46) will allow you to select a foreign table and the columns that
should be part of the foreign key. We will create a foreign key between the
username column in MailAddress and the username column in User. After
selecting you local column you can enter what it corresponds to by select-
ing it in the drop-down list across, Figure 47. You can also set condition
for if the key it referencing is deleted or updated, for example, a person
changes their username. Set the behavior to what is appropriate for your
35
Figure 46: Popup to create a foreign key
case, see Figure 48. Then press create, and the foreign key will be created.
In MailGoesTo we have two columns that are part of the same foreign key
and have to create a composite key with both columns. Follow the same
steps as previously with the difference that you select both columns instead
of just one, see Figure 49. After that press create and the foreign key will
be created.
36
Figure 47: Popup to create a foreign key
37
Figure 48: Filled popup to create foreign key
38
Figure 49: Filled popup to create composite foreign key
39
5.7 Inserting Data
To insert data in SQLiteStudio you press the data button, Figure 50, on the
top of table view. After pressing it you will be presented with a data window,
see Figure 51. Press the green plus to add a row. You can now enter the
data for the columns in the table. Press the green checkmark to save the
40
data, Figure 52.
as it will save your queries. After pressing create view you will be presented
with a blank window (Figure 54) where you can write your query and in the
top you can enter your view name. After you have written your query you
41
Figure 55: Results from the query
saved views will be shown in the view list right below your tables, Figure 56.
42
Figure 56: All views in the database
6 SQLite ERD
SQLite ERD is an application that can be used to create Entity Relation-
ship Diagrams (ERDs) for SQLite databases. The application is platform-
independent and is used within a web browser. The application can be
found at https://sqlite-erd.e-su.se/. For the interested reader, the
43
source code can be found at https://github.com/Edwinexd/sqlite-erd.
The application supports most common file formats for SQLite databases,
only requiring that the file is a SQLite database of version 3.
The application also performs some semantic analysis on the database,
such as checking for foreign key datatypes and ensuring that foreign
columns are unique.
The complete implemented database model can be seen in, Figure 57
Figure 57: The table is not available in the dropdown list of tables to refer-
ence.
7 Final Words
If you have any questions or issues with the tools presented in this doc-
ument or the document itself, please create an issue at https://github.
com/Edwinexd/db-sqlite-tools/issues.
44
References
[1] SQLite, “Date and time functions,” https://www.sqlite.org/lang_datefunc.
html#tmval, accessed: 2025-02-26.
[2] 0xcrypto et al., “The SQL generated for SQLite creates the primary
key twice on save (persist),” https://github.com/dbeaver/dbeaver/issues/
18491, 2022, accessed: 2024-12-16.
45