Using SQL as an every day tool

Every now and then I find myself in the situation where I need to analyze data coming varying sources, be it in the form of files (spreadsheets, CSV, etc.) or data spread across different servers and/or database platforms. The way that I often see people handle this is by loading the data into a spreadsheet (using Excel, LibreOffice or an alternative) and then start filtering and fidgeting away with spreadsheet formulas and functions, creating temporary columns and/or copying and pasting things around until they get their desired result. When you only have to examine a single table of data this is not much of an issue, it may in fact be the best option to start with: its low-barrier and using column filters is pretty intuitive in most spreadsheet software that I’ve used.

When your searching and filtering needs become more complicated and/or involve multiple tables of data that you want to combine in one way or another things tend to get a bit hairy (at least for me) and I personally prefer using SQL instead. In this article I will give an in-depth explanation on how you can do that using a contrived example, if you are experienced with SQL, command line tools and the shell you can probably skim large parts of this article, if most of this is new to you it hopefully contains enough detail for you to follow along.

In this article I’m going to show you how to use SQLite, this is my preferred database of choice for this type of work for a number of reasons: it’s lightweight (you do not require a database server process to run on your machine constantly), portable (it saves all its data in a single file that you can send to someone else which they can then access using SQLite ), open source and freely available for many platforms (including Windows, Mac OS and Linux).

The example

You own a small shop that sells a variety of products. You keep track of the products that you sell in a spreadsheet and your till can export all the sales into a CSV file.

Product idDescriptionCategorySales Price
1Blue JeansClothing25.00
2Red ShirtClothing15.00
3Red Soccer BallSports7.50
4Blue Suede ShoesClothing75.00
5Green Soccer BallSports7.50
Products file
Receipt nrDateProduct idQuantityPrice
12020-08-171125.00
12020-08-174160.00
22020-08-18517.50
32020-08-183212.50
42020-08-192115.00
Sample of till export

You want to combine the data from both sources and perform an analysis to become a more successful entrepreneur.

Getting SQLite

In this article I’m working with the command line interface to SQLite. You can (and if you want to follow along should) download the executable from the download page on the SQLite website. Look for a download matching your platform with a description that includes something along the lines of “A bundle of command-line tools for managing SQLite database files, including the command-line shell program”. Once you’ve downloaded the appropriate zip file unzip it in a convenient location.

Running SQLite goes by running “sqlite3” (or “sqlite3.exe” on Windows), which is one of the files contained inside the zip file. If you want to execute it from anywhere you will have to add it it your shell path, alternatively you can enter the full path to the executable to run it.

If you’re using Linux you can likely install SQLite using your distributions’ package manager, you are however very likely to get an older version of SQLite that does not support all the features mentioned in this article (which happens to be case with the version in the Ubuntu 20.04 repositories). Installing it through a package manager will usually add the executables to your shell path automatically. In this article I am working with version 3.33.0, downloaded from the SQLite website, which is the latest version at the time of this writing.

Loading data

The example files that I am providing with this article are in CSV format, in real world situations you will likely come across spreadsheets as well. Most spreadsheet programs can convert spreadsheets into CSV files, you will have to do that before you can import any of them into a SQLite database (make sure the delimiter of your CSV file is a comma and not a semicolon, otherwise your import will yield unexpected results).

To follow along (and experiment further) you can download my example files products.csv and sales.csv and open a shell (or DOS box in Windows). Go to the directory (or folder if you prefer that term) where you stored these files and start SQLite using the sqlite3 executable. If you are having trouble starting SQLite from its location and/or including it in your shell’s path you cann also opt to the CSV files in the same directory where you put the SQLite executables.

If you start the executable sqlite3 without any arguments it will work with an in memory database, the moment you exit the program all the data in it will vanish.

cor@nomac in ~/Documents/shop at 11:37:08 CEST 
➜  ./sqlite3          
SQLite version 3.33.0 2020-08-14 13:23:32
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> 

If you start it with a database name then it will store its data in a database with the filename you entered, without a path specification the file will be in your current directory.

cor@nomac in ~/Documents/shop at 07:58:46 CEST 
➜  ./sqlite3 shop.db
SQLite version 3.33.0 2020-08-14 13:23:32
Enter ".help" for usage hints.
sqlite>  

Now that we have a database at our disposal we can import data into it, SQLite offers its own .import command to do that. In the simplest form you simply import a CSV file as a new table like so:

sqlite> .import products.csv products --csv

That command we have just entered created a products table using the products.csv file as the source. The headings of the CSV file are now the column names in your table and each row has become a record.

The downside of this method is that all the columns are now text columns:

sqlite> .schema products
CREATE TABLE products(
  "Product id" TEXT,
  "Description" TEXT,
  "Category" TEXT,
  "Sales Price" TEXT
);

Ideally we would like the “Sales Price” column to be a number. Due to the limitations of SQLite we can’t simply change the data type of an existing column (which is a common feature in other databases), instead we will have to create the table first, with the appropriate columns and data types, and then import the data afterwards.

Let’s delete the products table and re-create it with the proper data types:

sqlite> DROP TABLE products;
sqlite> CREATE TABLE products (
   ...> product_id INT,
   ...> description TEXT,
   ...> category TEXT,
   ...> sales_price REAL
   ...> );

The CREATE TABLE statement defines a new products table for us to use, I have changed the column names to be all lower case and no longer include spaces (but instead use underscores) to make using them in SQL statements easier (spaces in column names really complicate things). For readability I have typed SQL keywords in uppercase, this is however not a requirement (e.g. “drop table” is equivalent to “DROP TABLE”), so when you are typing in SQL commands you do not need to put anything in uppercase.

In order to import the data into an existing table we need to skip the first row (which contains the column titles):

sqlite> .import products.csv products --csv --skip 1

Let’s quickly inspect the data that we have loaded:

sqlite> SELECT * FROM products;
1|Blue Jeans|Clothing|25.0
2|Red Shirt|Clothing|15.0
3|Red Soccer Ball|Sports|7.5
4|Blue Suede Shoes|Clothing|75.0
5|Green Soccer Ball|Sports|7.5

If you’re not already familiar with it, the SELECT statement is a SQL statement to query data, and in the above example we simply list all the records in the table. Later on in this article we will get back to that. For now you will probably notice that the above output is kind of hard to read, let’s fix that first. SQLite has different output modes, you can query and change the output mode using the .mode command.

sqlite> .mode
current output mode: list

The current (and default) output mode is list, on the shell I find table to be easier to read.

sqlite> .mode table
sqlite> SELECT * FROM products;
+------------+-------------------+----------+-------------+
| product_id |    description    | category | sales_price |
+------------+-------------------+----------+-------------+
| 1          | Blue Jeans        | Clothing | 25.0        |
| 2          | Red Shirt         | Clothing | 15.0        |
| 3          | Red Soccer Ball   | Sports   | 7.5         |
| 4          | Blue Suede Shoes  | Clothing | 75.0        |
| 5          | Green Soccer Ball | Sports   | 7.5         |
+------------+-------------------+----------+-------------+

Now let’s continue and get the sales data into our database, since we already know what the file looks like we can go ahead and create the table first and then import the data.

sqlite> CREATE TABLE sales (
   ...> receipt_nr INT,
   ...> date TEXT,
   ...> product_id INT,
   ...> quantity INT,
   ...> price REAL
   ...> );
sqlite> .import sales.csv sales --csv --skip 1
sqlite> SELECT * FROM sales;
+------------+------------+------------+----------+-------+
| receipt_nr |    date    | product_id | quantity | price |
+------------+------------+------------+----------+-------+
| 1          | 2020-08-17 | 1          | 1        | 25    |
| 1          | 2020-08-17 | 4          | 1        | 60    |
| 2          | 2020-08-18 | 5          | 1        | 7.5   |
| 3          | 2020-08-18 | 3          | 2        | 12.5  |
| 4          | 2020-08-19 | 2          | 1        | 15    |
| 5          | 2020-08-19 | 2          | 3        | 10    |
| 6          | 2020-08-19 | 4          | 1        | 75    |
+------------+------------+------------+----------+-------+

Running the .import command on an existing table will add more data to that table, existing data is left as is. Since the tables in this example have no restrictions nothing prevents you from inserting duplicate rows corrupting your results (like you would be able to duplicate data in any spreadsheet). SQLite (like many databases) offers provisions to prevent that, you can for example add unique constraints on your tables, that is however a bit beyond the scope of this article.

Using SQL queries

If you are already familiar with SQL then you can skip over this section because it likely does not contain anything new for you, if not then please do read on.

So far all we have done could have been done just as easily with a spreadsheet program, we could have simply loaded both tables into different sheets and we would have had the same results: two tables of data that we can look at. Let’s use SQL to give us the sales data combined with product information:

sqlite> SELECT * FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;
+------------+------------+------------+----------+-------+------------+-------------------+----------+-------------+
| receipt_nr |    date    | product_id | quantity | price | product_id |    description    | category | sales_price |
+------------+------------+------------+----------+-------+------------+-------------------+----------+-------------+
| 1          | 2020-08-17 | 1          | 1        | 25.0  | 1          | Blue Jeans        | Clothing | 25.0        |
| 1          | 2020-08-17 | 4          | 1        | 60.0  | 4          | Blue Suede Shoes  | Clothing | 75.0        |
| 2          | 2020-08-18 | 5          | 1        | 7.5   | 5          | Green Soccer Ball | Sports   | 7.5         |
| 3          | 2020-08-18 | 3          | 2        | 12.5  | 3          | Red Soccer Ball   | Sports   | 7.5         |
| 4          | 2020-08-19 | 2          | 1        | 15.0  | 2          | Red Shirt         | Clothing | 15.0        |
| 5          | 2020-08-19 | 2          | 3        | 10.0  | 2          | Red Shirt         | Clothing | 15.0        |
| 6          | 2020-08-19 | 4          | 1        | 75.0  | 4          | Blue Suede Shoes  | Clothing | 75.0        |
+------------+------------+------------+----------+-------+------------+-------------------+----------+-------------+

Using SQL we linked the tables together through the product_id column on both tables, the output is a bit verbose though as it shows duplicate information (there are two columns with the product_id).

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;
+------------+------------+------------+-------------------+----------+----------+-------------+-------+
| receipt_nr |    date    | product_id |    description    | category | quantity | sales_price | price |
+------------+------------+------------+-------------------+----------+----------+-------------+-------+
| 1          | 2020-08-17 | 1          | Blue Jeans        | Clothing | 1        | 25.0        | 25.0  |
| 1          | 2020-08-17 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 60.0  |
| 2          | 2020-08-18 | 5          | Green Soccer Ball | Sports   | 1        | 7.5         | 7.5   |
| 3          | 2020-08-18 | 3          | Red Soccer Ball   | Sports   | 2        | 7.5         | 12.5  |
| 4          | 2020-08-19 | 2          | Red Shirt         | Clothing | 1        | 15.0        | 15.0  |
| 5          | 2020-08-19 | 2          | Red Shirt         | Clothing | 3        | 15.0        | 10.0  |
| 6          | 2020-08-19 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 75.0  |
+------------+------------+------------+-------------------+----------+----------+-------------+-------+

I find the above table more natural to read, we have a list of receipts enriched with product data. With SQL you can use all sorts of arbitrary filters, let’s say we want to see all items sold with “red” somewhere in the description:

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> WHERE p.description LIKE '%red%';
+------------+------------+------------+-----------------+----------+----------+-------------+-------+
| receipt_nr |    date    | product_id |   description   | category | quantity | sales_price | price |
+------------+------------+------------+-----------------+----------+----------+-------------+-------+
| 4          | 2020-08-19 | 2          | Red Shirt       | Clothing | 1        | 15.0        | 15.0  |
| 5          | 2020-08-19 | 2          | Red Shirt       | Clothing | 3        | 15.0        | 10.0  |
| 3          | 2020-08-18 | 3          | Red Soccer Ball | Sports   | 2        | 7.5         | 12.5  |
+------------+------------+------------+-----------------+----------+----------+-------------+-------+

The WHERE part of the query sets the criteria to filter on, using a LIKE allows you to use pattern matching and the % is a wildcard (meaning: match anything). As you can see the query is case insensitive (Red is treated the same as red).

Let’s say we want to see all items sold with “red” somewhere in the description or that are in the category clothing:

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> WHERE p.description LIKE '%red%' OR p.category = 'Clothing';
+------------+------------+------------+------------------+----------+----------+-------------+-------+
| receipt_nr |    date    | product_id |   description    | category | quantity | sales_price | price |
+------------+------------+------------+------------------+----------+----------+-------------+-------+
| 1          | 2020-08-17 | 1          | Blue Jeans       | Clothing | 1        | 25.0        | 25.0  |
| 4          | 2020-08-19 | 2          | Red Shirt        | Clothing | 1        | 15.0        | 15.0  |
| 5          | 2020-08-19 | 2          | Red Shirt        | Clothing | 3        | 15.0        | 10.0  |
| 3          | 2020-08-18 | 3          | Red Soccer Ball  | Sports   | 2        | 7.5         | 12.5  |
| 1          | 2020-08-17 | 4          | Blue Suede Shoes | Clothing | 1        | 75.0        | 60.0  |
| 6          | 2020-08-19 | 4          | Blue Suede Shoes | Clothing | 1        | 75.0        | 75.0  |
+------------+------------+------------+------------------+----------+----------+-------------+-------+

Let’s do something useful and list all items sold at a discount (where less was paid per item than the sales price). Before we start filtering let’s see if we can make it visual:

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price, (price / quantity) AS paid_per_item
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;
+------------+------------+------------+-------------------+----------+----------+-------------+-------+------------------+
| receipt_nr |    date    | product_id |    description    | category | quantity | sales_price | price |  paid_per_item   |
+------------+------------+------------+-------------------+----------+----------+-------------+-------+------------------+
| 1          | 2020-08-17 | 1          | Blue Jeans        | Clothing | 1        | 25.0        | 25.0  | 25.0             |
| 1          | 2020-08-17 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 60.0  | 60.0             |
| 2          | 2020-08-18 | 5          | Green Soccer Ball | Sports   | 1        | 7.5         | 7.5   | 7.5              |
| 3          | 2020-08-18 | 3          | Red Soccer Ball   | Sports   | 2        | 7.5         | 12.5  | 6.25             |
| 4          | 2020-08-19 | 2          | Red Shirt         | Clothing | 1        | 15.0        | 15.0  | 15.0             |
| 5          | 2020-08-19 | 2          | Red Shirt         | Clothing | 3        | 15.0        | 10.0  | 3.33333333333333 |
| 6          | 2020-08-19 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 75.0  | 75.0             |
+------------+------------+------------+-------------------+----------+----------+-------------+-------+------------------+

Now let’s filter away:

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price, (price / quantity) AS paid_per_item
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> WHERE paid_per_item < sales_price;
+------------+------------+------------+------------------+----------+----------+-------------+-------+------------------+
| receipt_nr |    date    | product_id |   description    | category | quantity | sales_price | price |  paid_per_item   |
+------------+------------+------------+------------------+----------+----------+-------------+-------+------------------+
| 1          | 2020-08-17 | 4          | Blue Suede Shoes | Clothing | 1        | 75.0        | 60.0  | 60.0             |
| 3          | 2020-08-18 | 3          | Red Soccer Ball  | Sports   | 2        | 7.5         | 12.5  | 6.25             |
| 5          | 2020-08-19 | 2          | Red Shirt        | Clothing | 3        | 15.0        | 10.0  | 3.33333333333333 |
+------------+------------+------------+------------------+----------+----------+-------------+-------+------------------+

You can filter down further if you want, for example only showing clothing sold at a discount with blue somewhere in it’s description:

sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price, (price / quantity) AS paid_per_item
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> WHERE paid_per_item < sales_price AND p.description LIKE '%blue%' AND p.category = 'Clothing';
+------------+------------+------------+------------------+----------+----------+-------------+-------+---------------+
| receipt_nr |    date    | product_id |   description    | category | quantity | sales_price | price | paid_per_item |
+------------+------------+------------+------------------+----------+----------+-------------+-------+---------------+
| 1          | 2020-08-17 | 4          | Blue Suede Shoes | Clothing | 1        | 75.0        | 60.0  | 60.0          |
+------------+------------+------------+------------------+----------+----------+-------------+-------+---------------+

Besides filtering you can also do all sorts of calculations based on grouped data, for example making a list of items sold per category:

sqlite> SELECT p.category, SUM(s.quantity), SUM(s.price)
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> GROUP BY category;
+----------+-----------------+--------------+
| category | SUM(s.quantity) | SUM(s.price) |
+----------+-----------------+--------------+
| Clothing | 7               | 185.0        |
| Sports   | 3               | 20.0         |
+----------+-----------------+--------------+

And this can be done with filters too:

sqlite> SELECT p.category, SUM(s.quantity), SUM(s.price)
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id
   ...> WHERE p.description LIKE '%red%'
   ...> GROUP BY category;
+----------+-----------------+--------------+
| category | SUM(s.quantity) | SUM(s.price) |
+----------+-----------------+--------------+
| Clothing | 4               | 25.0         |
| Sports   | 2               | 12.5         |
+----------+-----------------+--------------+

Exporting data

Once you quit out of SQLite (which you can do with the .exit command, or alternatively in Linux with the key combination CTRL+d) the data is persisted to the file shop.db (in the same directory where you started the sqlite3 program). You can share this file with other people (by putting it on a USB stick, sending it an e-mail or through some other media or service) and they can open it using a compatible version of SQLite and run queries on it.

You will however regularly want to share the data in the form of spreadsheets or CSV files again for all sorts of reasons. SQLite of course offers facilities to do that.

Let’s export the earlier made overview of sales with product information to a CSV file:

sqlite> .headers on
sqlite> .mode csv
sqlite> .once ./report.csv
sqlite> SELECT s.receipt_nr, s.date, p.product_id, p.description, p.category, s.quantity, p.sales_price, s.price
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;

Let’s break down what the commands above do:

  • .headers turns on column headings for exports (otherwise you would just have a file with data without knowing which is which)
  • .mode changes the output mode to CSV
  • .once changes the output direction from the console to the given file for the next SQL query only (in this case report.csv in the directory where we started SQLite)

The resulting file looks like this:

receipt_nr,date,product_id,description,category,quantity,sales_price,price
1,2020-08-17,1,"Blue Jeans",Clothing,1,25.0,25.0
1,2020-08-17,4,"Blue Suede Shoes",Clothing,1,75.0,60.0
2,2020-08-18,5,"Green Soccer Ball",Sports,1,7.5,7.5
3,2020-08-18,3,"Red Soccer Ball",Sports,2,7.5,12.5
4,2020-08-19,2,"Red Shirt",Clothing,1,15.0,15.0
5,2020-08-19,2,"Red Shirt",Clothing,3,15.0,10.0
6,2020-08-19,4,"Blue Suede Shoes",Clothing,1,75.0,75.0

Using SQL we can change the resulting column headings in one go too:

sqlite> .mode table
sqlite> SELECT s.receipt_nr AS 'Receipt nr', s.date AS 'Date', p.product_id AS 'Product id',
   ...> p.description AS 'Description', p.category AS 'Category', s.quantity AS 'Quantity',
   ...> p.sales_price AS 'Sales Price', s.price AS 'Sold for'
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;
+------------+------------+------------+-------------------+----------+----------+-------------+----------+
| Receipt nr |    Date    | Product id |    Description    | Category | Quantity | Sales Price | Sold for |
+------------+------------+------------+-------------------+----------+----------+-------------+----------+
| 1          | 2020-08-17 | 1          | Blue Jeans        | Clothing | 1        | 25.0        | 25.0     |
| 1          | 2020-08-17 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 60.0     |
| 2          | 2020-08-18 | 5          | Green Soccer Ball | Sports   | 1        | 7.5         | 7.5      |
| 3          | 2020-08-18 | 3          | Red Soccer Ball   | Sports   | 2        | 7.5         | 12.5     |
| 4          | 2020-08-19 | 2          | Red Shirt         | Clothing | 1        | 15.0        | 15.0     |
| 5          | 2020-08-19 | 2          | Red Shirt         | Clothing | 3        | 15.0        | 10.0     |
| 6          | 2020-08-19 | 4          | Blue Suede Shoes  | Clothing | 1        | 75.0        | 75.0     |
+------------+------------+------------+-------------------+----------+----------+-------------+----------+

You can use the .once command to directly open the resulting file in your system’s default text edit like so:

sqlite> .mode csv
sqlite> .once -e ./report.csv
sqlite> SELECT s.receipt_nr AS 'Receipt nr', s.date AS 'Date', p.product_id AS 'Product id',
   ...> p.description AS 'Description', p.category AS 'Category', s.quantity AS 'Quantity',
   ...> p.sales_price AS 'Sales Price', s.price AS 'Sold for'
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;

The above resulted in my system opening up the updated report.csv file that now looks like this:

"Receipt nr",Date,"Product id",Description,Category,Quantity,"Sales Price","Sold for"
1,2020-08-17,1,"Blue Jeans",Clothing,1,25.0,25.0
1,2020-08-17,4,"Blue Suede Shoes",Clothing,1,75.0,60.0
2,2020-08-18,5,"Green Soccer Ball",Sports,1,7.5,7.5
3,2020-08-18,3,"Red Soccer Ball",Sports,2,7.5,12.5
4,2020-08-19,2,"Red Shirt",Clothing,1,15.0,15.0
5,2020-08-19,2,"Red Shirt",Clothing,3,15.0,10.0
6,2020-08-19,4,"Blue Suede Shoes",Clothing,1,75.0,75.0

If you have a spreadsheet program installed you can let SQLite attempt to open it in that program instead of a text editor by using the -x switch instead of the -e switch like so:

sqlite> .once -x ./report.csv
sqlite> SELECT s.receipt_nr AS 'Receipt nr', s.date AS 'Date', p.product_id AS 'Product id',
   ...> p.description AS 'Description', p.category AS 'Category', s.quantity AS 'Quantity',
   ...> p.sales_price AS 'Sales Price', s.price AS 'Sold for'
   ...> FROM sales AS s JOIN products AS p ON p.product_id = s.product_id;

For most spreadsheet programs that will trigger an import wizard where you can define the data types of each of the colums. Getting your spreadsheet to look more presentable for you to share (changing fonts, colors, adding autofilters, etc.) then remain as manual steps before saving it and sending it out.

In conclusion

You have come to the end of this article and have now hopefully gotten the basics you need to start using SQL with SQLite to your advantage. There is of course a lot more that you can do than what I have shown here, if you want to learn more about SQLite there is quite a bit of documentation on the SQLite website (see https://sqlite.org/lang.html for example on more information on the supported SQL syntax). Additionally you can use the build in .help command to get more information on the available SQLite commands (running .help .import will for example explain the .import command that we used earlier).

You will find that with practice using SQLite is an easy and often a very quick way to work with and analyze data. If you have feedback on this article or have questions based on its contents then feel free to reach out to me on Twitter or through e-mail.