Lecture 15: Aliasing and Logicals
September 1, 2026
π Last lecture we looked at:
π Today we will emphasize querying and modifying data:
We will continue working with the Chinook database with structure:

Each arrow represents a foreign-key relationship β it shows how a column in one table references the primary key of another, letting us connect data across tables.
Last time we learned how to connect to an external database. Make sure you have the appropriate libraries loaded.
Then create an appropriate database object:
π Things to watch out for:
If you do not have an appropriate file path pointing to the .sqlite file, R will populate an empty database object.
If you wish to avoid working with file paths, place the .sqlite file in your current working directory.
Recall our basic SQL query from last lecture that had the following structure:
We also saw the INSERT and LIMIT arguments in these SQL queries.
Suppose we wanted to select all attributes of the invoice table.
βΌοΈ This is going to be a hefty query β but we know how to write it!

Written out in full we have:
InvoiceId CustomerId InvoiceDate BillingAddress BillingCity
1 1 2 2009-01-01 00:00:00 Theodor-Heuss-StraΓe 34 Stuttgart
2 2 4 2009-01-02 00:00:00 UllevΓ₯lsveien 14 Oslo
BillingState BillingCountry BillingPostalCode Total
1 <NA> Germany 70174 1.98
2 <NA> Norway 0171 3.96
* SyntaxInstead, to select all attributes we can use the * symbol:
InvoiceId CustomerId InvoiceDate BillingAddress BillingCity
1 1 2 2009-01-01 00:00:00 Theodor-Heuss-StraΓe 34 Stuttgart
2 2 4 2009-01-02 00:00:00 UllevΓ₯lsveien 14 Oslo
BillingState BillingCountry BillingPostalCode Total
1 <NA> Germany 70174 1.98
2 <NA> Norway 0171 3.96
π When in doubt, keep your queries simple! π
select()Sometimes it may be helpful to combine functionality across different languages:
tidyverse if you have not already done so; andsqldf if you have not already done so.'data.frame': 412 obs. of 3 variables:
$ InvoiceId : int 1 2 3 4 5 6 7 8 9 10 ...
$ BillingCity: chr "Stuttgart" "Oslo" "Brussels" "Edmonton" ...
$ Total : num 1.98 3.96 5.94 8.91 13.86 ...
Remember, dbGetQuery() returns the query result as a dataframe:
select() function to select columns.str() function to examine our results.WHERE beforeβ¦The syntax WHERE allows us to work with logicals. Make sure to think carefully about the logic you are trying to implement.
The syntax AND and OR allow us to select intersections and unions respectively:
BillingCity BillingCountry Total
1 Budapest Hungary 21.86
Combine clauses similarly to combining R logical expressions.
BillingCity BillingCountry Total
1 Rome Italy 1.98
2 Rome Italy 3.96
3 Budapest Hungary 21.86
4 Rome Italy 5.94
AND is evaluated before OR. BillingCity BillingCountry Total
1 Rome Italy 1.98
2 Rome Italy 3.96
3 Rome Italy 5.94
4 Rome Italy 0.99
5 Rome Italy 1.98
6 Rome Italy 13.86
Sometimes we wish to exclude specific values. Suppose we wanted all invoices where the total is NOT .99:
This NOT syntax is very powerful when combined with the AND, OR commands.
SQL tries to closely mimic human language:
AND, OR, NOT used rather than &, |, !NOT (negated clause) operator breaks (English) language convention slightly. SQL also allows the <> operator to mean not equal:π The syntax != does work in SQLite but not universally. Please use the <> convention whenever possible.
04:00
Write and execute a SQL query that retrieves the InvoiceId, InvoiceDate, BillingCity, BillingState and Total for all invoices of customers based in the United States who spent between $15 and $20.
InvoiceId InvoiceDate BillingCity BillingState Total
1 103 2010-03-21 00:00:00 Chicago IL 15.86
2 201 2011-05-29 00:00:00 Madison WI 18.86
This query works, i.e. it returns the desired values β but:
BETWEEN is helpful.A better solution uses BETWEEN:
InvoiceId InvoiceDate BillingCity BillingState Total
1 103 2010-03-21 00:00:00 Chicago IL 15.86
2 201 2011-05-29 00:00:00 Madison WI 18.86
Why is this better?
BETWEEN is inclusive of both bounds β equivalent to >= 15 AND <= 20.$15 and $20β.It is often useful to know which attribute values exist in a table.
SELECT DISTINCT allows us to pick only unique values.Sometimes we wish to know the number of unique values using the syntax COUNT:
COUNT can also be used independently of DISTINCT:
Suppose we want to see the invoice totals ordered from minimum to maximum. We can use the ORDER BY query.
To sort in descending order we would write:
MIN() and MAX() FunctionsThe MIN() and MAX() functions isolate the smallest and largest values:
BillingCountry BillingCity MIN(Total)
1 Germany Frankfurt 0.99
π Note the behavior in the case of ties.
05:00
Write and execute an SQL query that:
TrackId, Name, AlbumId, GenreId attributes of Track. TrackId Name AlbumId GenreId
1 3 Fast As a Shark 3 1
2 4 Restless and Wild 3 1
3 93 Exploder 10 1
4 94 Hypnotize 10 1
5 1146 Welcome to the Jungle 90 1
Breaking it down:
BETWEEN filters joined with AND β one on duration (Milliseconds), one on size (Bytes).ORDER BY UnitPrice DESC returns tracks in descending order by price.LIMIT 5 caps the output at five rows.Error messages are good. Odd returns are much worse!
Whatβs happening here?
π This is not an error: - SELECT 'ucsb' returns the string literal 'ucsb' for every matched row. - SELECT can return more than just column values.
SELECT is an incredibly flexible tool! Name AlbumId
1 Fast As a Shark 3
2 Restless and Wild 3
3 Princess of the Dawn 3
'ucsb' Name AlbumId
1 ucsb Fast As a Shark 3
2 ucsb Restless and Wild 3
3 ucsb Princess of the Dawn 3
SELECT can also return computed values: 'ucsb' power(2, 5) Name
1 ucsb 32 Fast As a Shark
2 ucsb 32 Restless and Wild
3 ucsb 32 Princess of the Dawn
Bytes / Milliseconds Name
1 17 Fast As a Shark
2 17 Restless and Wild
3 16 Princess of the Dawn
Aliasing assigns a temporary name to a column (or table) that exists for the duration of the query only.
FROM table AS alias syntax.WHERE clauses can reference columns by alias.Sometimes we donβt know quite what weβre looking for.
SQLite gives us two pattern-matching operators:
LIKE β simple wildcards (%, _), case-insensitive.GLOB β Unix-style wildcards (*, ?), case-sensitive.π Reach for LIKE first β it is simpler and covers most cases. Use GLOB when you need case sensitivity or finer control.
LIKESelection based on first letter only:
LIKE β Intermediate StringsSelection based on intermediate string:
GLOB PrecisionSQLiteβs GLOB operator matches text values against a pattern using wildcards β * for any sequence of characters and ? for a single character.
GLOB allows further precision and refinement in these queries:
05:00
Write and execute an SQL query that:
TrackId and Name of all tracks with AlbumId = 30.Seconds.MB.and in their names.Breaking it down:
SELECT with arithmetic and alias them β Milliseconds/1000 AS Seconds and Bytes*power(10, -6) AS MB.LIKE '% and %' uses surrounding spaces to match the word βandβ, not substrings like βlandβ.ORDER BY Seconds ASC sorts by the alias we just defined.Much like R, SQL code works without proper styling.
Indentation should follow logical functions:
π Specific indentation is subjective, but your focus should be to make your code as readable as possible.
π€ This lecture covered many aspects of SQL code and syntax:
WHERESELECTLIMIT, ORDER BY, *, etc.)π In general you shouldnβt focus on memorizing syntax β instead focus on understanding it and using it to solve problems.
π€© Next class we will almost entirely focus on two topics:
COUNT, MIN, MAX, etc.)Then, in lectures 17 and 18, we will cover a selection of more advanced SQL topics:
SELECT statements