2.1 Our Database Management System (DBMS) for this course
Client: R/RStudio w/ SQL
Database Engine: DuckDB
Data Storage: single file in data/ folder
2.2 Quick Tour of RStudio
2.3 Connecting to our database
To access the data, we need to create a database connection. We use dbConnect() from the DBI package to do this. The first argument specifies the Database engine (duckdb()), and the second provides the file location: "data/data/GiBleed_5.3_1.1.duckdb".
duckdb is storing downloaded extensions and secrets under ~/.duckdb:
i /Users/tladera2/.duckdb
This persists across sessions and is shared with the DuckDB CLI and other clients.
i Run duckdb(shared_home = FALSE) to use a temporary directory instead.
i See ?duckdb_storage for details and alternatives.
Once open, we can use con (our database connection)
2.4 Keep in Mind: SQL ignores letter case
These are the same to the database engine:
SELECT person_id FROM person;
select PERSON_ID FROM person;
And so on. Our convention is that we capitalize SQL clauses such as SELECT so you can differentiate them from other information.
2.5 Looking at the Entire Database
One of the first things we can learn is to show the contents of the entire database; we can do this with SHOW TABLES:
SHOW TABLES;
Displaying records 1 - 10
name
care_site
cdm_source
concept
concept_ancestor
concept_class
concept_relationship
concept_synonym
condition_era
condition_occurrence
cost
We can get further information about the tables within our database using DESCRIBE; This will give us more information about individual tables:
procedure_occurrence - procedures performed on patients and when they happened
concept - contains the specific information (names of concepts) that map into all three above tables
2.6 Describing a table
We can use DESCRIBE to get more information (the metadata) about a table.
DESCRIBE person
Displaying records 1 - 10
column_name
column_type
null
key
default
extra
person_id
INTEGER
YES
NA
NA
NA
gender_concept_id
INTEGER
YES
NA
NA
NA
year_of_birth
INTEGER
YES
NA
NA
NA
month_of_birth
INTEGER
YES
NA
NA
NA
day_of_birth
INTEGER
YES
NA
NA
NA
birth_datetime
TIMESTAMP
YES
NA
NA
NA
race_concept_id
INTEGER
YES
NA
NA
NA
ethnicity_concept_id
INTEGER
YES
NA
NA
NA
location_id
INTEGER
YES
NA
NA
NA
provider_id
INTEGER
YES
NA
NA
NA
We will pay attention to column_name and column_type for the moment.
2.7 Data Types
If you look at the column_type for one of the DESCRIBE statements above, you’ll notice there are different data types:
INTEGER
TIMESTAMP
DATE
VARCHAR
Each column of a database needs to be typed. The data type of a column determines what kinds of calculations or operations we can do on them. For example, we can do things like date arithmetic on DATETIME columns, asking the engine to calculate 5 days after the dates.
Adding WHERE to our SQL statement lets us add filtering to our query:
SELECT person_id, gender_source_value, race_source_value, year_of_birth FROM person WHERE year_of_birth <2000
Displaying records 1 - 10
person_id
gender_source_value
race_source_value
year_of_birth
6
F
black
1963
123
M
white
1950
129
M
white
1974
16
F
white
1971
65
F
black
1967
74
F
white
1972
42
F
white
1909
187
M
white
1945
18
F
white
1965
111
F
white
1975
One critical thing to know is that you don’t need to include the columns you’re filtering on in the SELECT part of the statement. For example, we could do the following as well, removing year_of_birth from our SELECT:
SELECT person_id, gender_source_value, race_source_value FROM person WHERE year_of_birth <2000
Displaying records 1 - 10
person_id
gender_source_value
race_source_value
6
F
black
123
M
white
129
M
white
16
F
white
65
F
black
74
F
white
42
F
white
187
M
white
18
F
white
111
F
white
2.13.1 Single quotes and WHERE
SQL convention: single quotes (‘M’) refer to values, and double quotes refer to columns (“person_id”). If you try to use double quotes in the below, it will look for a column called “M”.
This will trip you up several times if you’re not used to it.
SELECT person_id, gender_source_value FROM person WHERE gender_source_value ='M'LIMIT10;
Displaying records 1 - 10
person_id
gender_source_value
123
M
129
M
187
M
40
M
53
M
78
M
69
M
248
M
105
M
49
M
Reminder: use single (’’) quotes in your SQL statements to refer to values, not double quotes (“).
2.13.2 Quick Note
For R users, notice the similarity of select() with SELECT. We can rewrite the above in dplyr code as:
A lot of dplyr was inspired by SQL. In fact, there is a package called dbplyr that translates dplyr statements into SQL. A lot of us use it, and it’s pretty handy.
2.14COUNT - how many entries?
Sometimes you want to know the size of your result, not necessarily return the entire set of results. That is what COUNT is for.
SELECTCOUNT(*)FROM procedure_occurrence;
1 records
count_star()
37409
Similarly, when we want to count the number of person_ids returned, we can use COUNT(person_id):
There are repeat procedure_concept_ids in the procedure_occurrence table. When you have repeated values in the rows, COUNT(DISTINCT ) can help you find the number of unique values in a column:
Count the distinct values of gender_source_value in person:
SELECTCOUNT(----)FROM-------
2.16 Revisiting DESCRIBE
Let’s return to our table metadata and look at it more in depth:
DESCRIBE person
Displaying records 1 - 10
column_name
column_type
null
key
default
extra
person_id
INTEGER
YES
NA
NA
NA
gender_concept_id
INTEGER
YES
NA
NA
NA
year_of_birth
INTEGER
YES
NA
NA
NA
month_of_birth
INTEGER
YES
NA
NA
NA
day_of_birth
INTEGER
YES
NA
NA
NA
birth_datetime
TIMESTAMP
YES
NA
NA
NA
race_concept_id
INTEGER
YES
NA
NA
NA
ethnicity_concept_id
INTEGER
YES
NA
NA
NA
location_id
INTEGER
YES
NA
NA
NA
provider_id
INTEGER
YES
NA
NA
NA
One of the important properties of data in a relational database is that there are no repeat rows in the database. Each table that meets this restriction has what is called a primary key.
Scanning the rows, which field/column is the primary key for person?
Try and find the primary key for procedure_occurrence. What is it?
DESCRIBE procedure_occurrence
Displaying records 1 - 10
column_name
column_type
null
key
default
extra
procedure_occurrence_id
INTEGER
YES
NA
NA
NA
person_id
INTEGER
YES
NA
NA
NA
procedure_concept_id
INTEGER
YES
NA
NA
NA
procedure_date
DATE
YES
NA
NA
NA
procedure_datetime
TIMESTAMP
YES
NA
NA
NA
procedure_type_concept_id
INTEGER
YES
NA
NA
NA
modifier_concept_id
INTEGER
YES
NA
NA
NA
quantity
INTEGER
YES
NA
NA
NA
provider_id
INTEGER
YES
NA
NA
NA
visit_occurrence_id
INTEGER
YES
NA
NA
NA
We'll see that primary keys need to be unique (so they can map to each row).
What column is the same in both tables? That is a hint for what we'll cover next week: JOINing tables.
2.17 Always close the connection
When we’re done, it’s best to close the connection with dbDisconnect().