Entity Relationship Diagram
Connect to the sqlite database file.
# connect to the sqlite database file
conn <- dbConnect(RSQLite::SQLite(), "daie_ca4_data.sqlite")
Contents of tables to check queries against.
Function to format tables for HTML and PDF output. Display tables using knitr library’s kable function and kableExtra to format tables.
# type parameter sets class type for different table formatting
# bgcolor parameter sets the table heading colour
# caprt paramter sets the table caption
# paste() used to concatenate strings
# sep - the separator in the concatenated string
# separate formatting is required for html and pdf tables due to css class error
# stripe_color sets alternate row colour for pdf tables and queries
data_format.function <- function(data, capt="", type="table", bgcolour="#28B3F9") {
data %>%
{
if (is_html_output()) { # if the output is HTML add class attribute
kbl(., caption = capt,
table.attr=paste("class='",type,"-striped ",type,'-',"hover'", sep="")) %>%
kable_styling(bootstrap_options = c("striped", "hover"))
}
else if (is_latex_output()) { # if the output is PDF ignore class attribute
kbl(., caption = capt) %>%
kable_styling(latex_options = c("striped","HOLD_position"),
stripe_color=ifelse((type == "table"),"#D3EDF9","#FBBBBB"))
}
} %>% # pdf output keep tables in position
row_spec(0, background = bgcolour) # table heading colour
}
Status table data.
SELECT * FROM Status -- get all data in Status table
data_format.function(status_data, "Status") # format data with function above
Id | Name |
---|---|
1 | To Do |
2 | In Progress |
3 | Review |
4 | Done |
Role table data.
SELECT * FROM Role -- get all data in Role table
data_format.function(role_data, "Role") # format data with function above
Id | Name |
---|---|
1 | Project Manager |
2 | Programmer |
3 | Tester |
4 | Artist |
5 | 3D Modeller |
6 | Environment Modeller |
7 | Animator |
8 | Shading Artist |
9 | Concept Artist |
Team_Member table data.
SELECT * FROM Team_Member -- get all data in Team_Member table
data_format.function(team_member_data, "Team Member") # format data with function above
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
1 | Joe | O’Regan | joe.oregan@daie.ca4 | 2 |
2 | Derp | McDerp | derpmcderp@daie.ca4 | 1 |
3 | Herpderp | Derpderpenson | hd.derpderpenson@daie.ca4 | 3 |
4 | Herpa | Derpderp | herpa.derpderp@daie.ca4 | 4 |
5 | De | Rpderp | de.rpderp@daie.ca4 | 5 |
6 | Pred | Prehpred | predprehpred@daie.ca4 | 6 |
7 | Derpa | Derpa | derpaderpa@daie.ca4 | 9 |
8 | Herpa | Derpa | herpaderpa@daie.ca4 | 8 |
9 | HerpaDerpa | McDerpa | herpaderpa.mcderpa@daie.ca4 | 7 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
11 | Jon | Herpaderp | jherpaderp@daie.ca4 | 7 |
12 | Joblot | O’Stuff | joblot.ostuff@daie.ca4 | 3 |
13 | Joderp | Herpderpenson | j.herpderpenson@daie.ca4 | 4 |
14 | Jo | McQueryfiller | j.mcqueryfiller@daie.ca4 | 1 |
Work_Item table data. Formatted differently (HTML output) to test different kableExtra formatting options.
SELECT * FROM Work_Item -- get all data in Work_Item table
# data_format.function(work_item_data, "Work Item") # format data with function above
data <- work_item_data # dataframe
data$Id = row.names(work_item_data)
row.names(data) <- NULL
# in HTML output format the Status_Id column so 1 (To Do) is red, and 4 (Done) is green
if (is_html_output()) {
data$Status_Id = cell_spec(data$Status_Id, color = "white",
background = ifelse(data$Status_Id == 4, "green",
ifelse(data$Status_Id == 1,
"red", "black")))
}
data <- data[c("Id", "Name", "Status_Id", "Assigned_To")] # error if not escaped for html
# data <- data.frame(data)
kbl(data, escape=ifelse(is_html_output(), FALSE, TRUE), caption = "Work Item") %>%
kable_styling(c("striped", "hover")) %>%
kable_styling(latex_options = "striped", stripe_color="#D3EDF9") %>% # pdf stripe colour
row_spec(0, background = "#28B3F9") # table heading colour
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
1 | Art Thingy | 2 | 4 |
2 | Art Test Thingy | 3 | 3 |
3 | Environment Model Thingy | 2 | 6 |
4 | Art Concept Thingy | 4 | 7 |
5 | Art Shading Thingy | 4 | 8 |
6 | Random 3D Model | 2 | 5 |
7 | 3D Model Test Obj | 2 | 3 |
8 | Random Blueprint | 2 | 1 |
9 | Blueprint Thingy | 2 | 2 |
10 | Blueprint Test | 3 | 2 |
11 | Art Test | 1 | 12 |
12 | Query Model Thingy | 3 | 11 |
13 | Another Test | 4 | 13 |
Project table data.
SELECT * FROM Project -- get all data in Project table
data_format.function(project_data, "Project") # format data with function above
Id | Name | Delivery_Date |
---|---|---|
1 | Art Proj | 2023-01-11 |
2 | DAIE CA4 | 2023-01-20 |
3 | New Project | 2023-01-24 |
4 | Old Project | 2022-12-14 |
5 | Christmas 2022 Project | 2022-12-25 |
6 | Date Range Project | 2023-01-17 |
7 | Another Date Range Project | 2023-02-01 |
8 | Project Filler | 2023-03-01 |
9 | Derp Project | 2023-03-17 |
10 | Hmmm I Ran Out of Names | 2023-01-20 |
Project_Team table data.
SELECT * FROM Project_Team -- get all data in Project_Team table
data_format.function(project_team_data, "Project Team") # format data with function above
Team_Member_Id | Project_Id |
---|---|
1 | 1 |
2 | 1 |
3 | 1 |
4 | 1 |
5 | 1 |
2 | 2 |
6 | 2 |
7 | 2 |
8 | 2 |
9 | 2 |
2 | 3 |
10 | 3 |
11 | 3 |
14 | 4 |
12 | 4 |
13 | 5 |
14 | 6 |
14 | 7 |
Asset table data.
SELECT * FROM Asset -- get all data in Asset table
data_format.function(asset_data, "Asset") # format data with function above
Id | Name | Type | Format | Created_By | Date_Created |
---|---|---|---|---|---|
1 | Random Blueprint Asset | Combination of Blueprints | Zip file | 1 | 2023-01-11 |
2 | Random Art Asset | NA | NA | 4 | 2023-01-10 |
3 | Art Asset Thingy | NA | NA | 4 | 2023-01-10 |
4 | Environment Asset Thingy | Tree for use in Environment | NA | 4 | 2023-01-02 |
Asset_Work_Items table data.
SELECT * FROM Asset_Work_Items -- get all data in Asset_Work_Items table
data_format.function(asset_work_items_data,
"Asset Work Items") # format data with function above
Work_Item_Id | Asset_Id |
---|---|
8 | 1 |
9 | 1 |
10 | 1 |
1 | 2 |
2 | 2 |
4 | 3 |
5 | 3 |
3 | 4 |
6 | 4 |
7 | 4 |
Library table data.
SELECT * FROM Library -- get all data in Library table
data_format.function(library_data, "Library") # format data with function above
Id | Name |
---|---|
1 | Programming |
2 | Models |
3 | Scenery |
4 | Characters |
Collection table data.
SELECT * FROM Collection -- get all data in Collection table
data_format.function(collection_data, "Collection") # format data with function above
Library_Id | Asset_Id |
---|---|
1 | 1 |
2 | 2 |
2 | 3 |
3 | 4 |
Query the above database using SQL queries demonstrating the following SQL concepts:
Find Team Members who have the first name Joe.
SELECT * FROM Team_Member WHERE First_Name = 'Joe';
Format the query output as a table with kable and kableExtra function above.
data_format.function(query1_select_with_where, "Team members with first name Joe",
"query", "#FF0000") # format data changing function defaults
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
1 | Joe | O’Regan | joe.oregan@daie.ca4 | 2 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
Using wildcards to substitute one or more characters in a string.
Find Team Members with first name with 3 characters beginning with “jo”
using ’_’ wildcard.
SELECT * FROM Team_Member WHERE First_Name LIKE "jo_";
data_format.function(query2a_select_with_like,
"Team members with name beginning with jo and at least 3 characters",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
1 | Joe | O’Regan | joe.oregan@daie.ca4 | 2 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
11 | Jon | Herpaderp | jherpaderp@daie.ca4 | 7 |
Find Team Members with last name containing the string “derp” using ‘%’
wildcard.
SELECT * FROM Team_Member WHERE Last_Name LIKE "%derp%";
data_format.function(query2b_select_with_like,
# need to escape \ and %
"Team member last name contains 'derp' string using \\% wildcard",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
2 | Derp | McDerp | derpmcderp@daie.ca4 | 1 |
3 | Herpderp | Derpderpenson | hd.derpderpenson@daie.ca4 | 3 |
4 | Herpa | Derpderp | herpa.derpderp@daie.ca4 | 4 |
5 | De | Rpderp | de.rpderp@daie.ca4 | 5 |
7 | Derpa | Derpa | derpaderpa@daie.ca4 | 9 |
8 | Herpa | Derpa | herpaderpa@daie.ca4 | 8 |
9 | HerpaDerpa | McDerpa | herpaderpa.mcderpa@daie.ca4 | 7 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
11 | Jon | Herpaderp | jherpaderp@daie.ca4 | 7 |
13 | Joderp | Herpderpenson | j.herpderpenson@daie.ca4 | 4 |
Find Team Members with first name beginning with “jo” with at least 3
characters, i.e. excludes “Jo”.
SELECT * FROM Team_Member WHERE First_Name LIKE "jo_%";
data_format.function(query2c_select_with_like,
"Team member first name of at least 3 characters beginning with 'jo'",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
1 | Joe | O’Regan | joe.oregan@daie.ca4 | 2 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
11 | Jon | Herpaderp | jherpaderp@daie.ca4 | 7 |
12 | Joblot | O’Stuff | joblot.ostuff@daie.ca4 | 3 |
13 | Joderp | Herpderpenson | j.herpderpenson@daie.ca4 | 4 |
Select Team Members where the Role_Id is 2 OR 7.
SELECT * FROM Team_Member WHERE Role_Id = 2 OR Role_Id = 7;
data_format.function(query3a_select_with_or, "Team member with role id of 2 or 7",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
1 | Joe | O’Regan | joe.oregan@daie.ca4 | 2 |
9 | HerpaDerpa | McDerpa | herpaderpa.mcderpa@daie.ca4 | 7 |
10 | Joe | Derp | j.derp@daie.ca4 | 2 |
11 | Jon | Herpaderp | jherpaderp@daie.ca4 | 7 |
Select Team Members whose first name is “Herpa” or last name is
“Derpa”.
SELECT * FROM Team_Member WHERE First_Name = "Herpa" OR Last_Name = "Derpa";
data_format.function(query3b_select_with_or,
"Team members with first name 'Herpa' or last name 'Derpa'",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
4 | Herpa | Derpderp | herpa.derpderp@daie.ca4 | 4 |
7 | Derpa | Derpa | derpaderpa@daie.ca4 | 9 |
8 | Herpa | Derpa | herpaderpa@daie.ca4 | 8 |
Find work items with Name beginning with a string like “art” or have a Status_Id of 3.
SELECT * FROM Work_Item WHERE Name LIKE "art%" OR Status_Id = 3;
data_format.function(query4a_select_with_where_like_or,
"Work item with name beginning with the string 'art'",
"query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
1 | Art Thingy | 2 | 4 |
2 | Art Test Thingy | 3 | 3 |
4 | Art Concept Thingy | 4 | 7 |
5 | Art Shading Thingy | 4 | 8 |
10 | Blueprint Test | 3 | 2 |
11 | Art Test | 1 | 12 |
12 | Query Model Thingy | 3 | 11 |
Find Work Items where the name doesn’t contain “Thingy”.
SELECT * FROM Work_Item WHERE Name NOT LIKE "%thingy%";
data_format.function(query4b_select_with_not,
"Work items that do not containt the string 'thingy'",
"query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
6 | Random 3D Model | 2 | 5 |
7 | 3D Model Test Obj | 2 | 3 |
8 | Random Blueprint | 2 | 1 |
10 | Blueprint Test | 3 | 2 |
11 | Art Test | 1 | 12 |
13 | Another Test | 4 | 13 |
Find the unique status IDs currently in the Work_Item table.
SELECT DISTINCT Status_Id FROM Work_Item;
data_format.function(query5_select_distinct,
"Get the unique values for Status Id in Work Item",
"query", "#FF0000") # format query
Status_Id |
---|
2 |
3 |
4 |
1 |
Display work items ordered by assigned_to (Team_Member.Id).
SELECT * FROM Work_Item ORDER BY Assigned_To;
data_format.function(query6_select_order_by,
"Show Work Items ordered by Assigned To ID number",
"query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
8 | Random Blueprint | 2 | 1 |
9 | Blueprint Thingy | 2 | 2 |
10 | Blueprint Test | 3 | 2 |
2 | Art Test Thingy | 3 | 3 |
7 | 3D Model Test Obj | 2 | 3 |
1 | Art Thingy | 2 | 4 |
6 | Random 3D Model | 2 | 5 |
3 | Environment Model Thingy | 2 | 6 |
4 | Art Concept Thingy | 4 | 7 |
5 | Art Shading Thingy | 4 | 8 |
12 | Query Model Thingy | 3 | 11 |
11 | Art Test | 1 | 12 |
13 | Another Test | 4 | 13 |
Display work items ordered by Status_Id (Status.Id) in ascending order.
SELECT * FROM Work_Item ORDER BY Status_Id ASC;
data_format.function(query7_select_order_by_asc,
"Show Work Items ordered by Status Id code", "query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
11 | Art Test | 1 | 12 |
1 | Art Thingy | 2 | 4 |
3 | Environment Model Thingy | 2 | 6 |
6 | Random 3D Model | 2 | 5 |
7 | 3D Model Test Obj | 2 | 3 |
8 | Random Blueprint | 2 | 1 |
9 | Blueprint Thingy | 2 | 2 |
2 | Art Test Thingy | 3 | 3 |
10 | Blueprint Test | 3 | 2 |
12 | Query Model Thingy | 3 | 11 |
4 | Art Concept Thingy | 4 | 7 |
5 | Art Shading Thingy | 4 | 8 |
13 | Another Test | 4 | 13 |
Display work items ordered by Assigned_To (Team_Member.Id) in descending order.
SELECT * FROM Work_Item ORDER BY Assigned_To DESC;
data_format.function(query8_select_order_by_desc,
"Work Items ordered by Assigned To ID number in descending order",
"query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
13 | Another Test | 4 | 13 |
11 | Art Test | 1 | 12 |
12 | Query Model Thingy | 3 | 11 |
5 | Art Shading Thingy | 4 | 8 |
4 | Art Concept Thingy | 4 | 7 |
3 | Environment Model Thingy | 2 | 6 |
6 | Random 3D Model | 2 | 5 |
1 | Art Thingy | 2 | 4 |
2 | Art Test Thingy | 3 | 3 |
7 | 3D Model Test Obj | 2 | 3 |
9 | Blueprint Thingy | 2 | 2 |
10 | Blueprint Test | 3 | 2 |
8 | Random Blueprint | 2 | 1 |
Display work items ordered by Assigned_To (Team_Member.Id) in descending order.
SELECT DISTINCT Assigned_To FROM Work_Item ORDER BY Assigned_To;
data_format.function(query9_select_distinct_order_by,
"Show distinct list of team members with work assigned to them",
"query", "#FF0000")
Assigned_To |
---|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
Show list of team members who have no work assigned to them (opposite of previous query).
SELECT Id, First_Name || ' ' || Last_Name AS "Name"
FROM Team_Member
WHERE Id NOT IN
(SELECT DISTINCT Assigned_To FROM Work_Item);
data_format.function(query9b,
"Show list of team members with no work assigned to them",
"query", "#FF0000")
Id | Name |
---|---|
9 | HerpaDerpa McDerpa |
10 | Joe Derp |
14 | Jo McQueryfiller |
Inner Join Team_Member and Role tables via foreign key Team_Member.Role_id corresponding to Role.Id.
First name and last name are concatenated with the || operator as Concat() doesn’t work in Sqlite. Using Alias (AS) for column headings and t for Team_Member and r for Role table aliases.
-- no Concat() in sqlite, || = concat operator
SELECT t.Id AS 'Member Id',
t.First_Name || ' ' || t.Last_Name AS 'Full Name',
r.Name AS 'Project Role'
FROM Team_Member t
Inner Join Role r
ON t.Role_Id = r.Id
data_format.function(query10a_select_inner_join,
"Team Member Inner Joins Role to display member name and role",
"query", "#FF0000") # format
Member Id | Full Name | Project Role |
---|---|---|
1 | Joe O’Regan | Programmer |
2 | Derp McDerp | Project Manager |
3 | Herpderp Derpderpenson | Tester |
4 | Herpa Derpderp | Artist |
5 | De Rpderp | 3D Modeller |
6 | Pred Prehpred | Environment Modeller |
7 | Derpa Derpa | Concept Artist |
8 | Herpa Derpa | Shading Artist |
9 | HerpaDerpa McDerpa | Animator |
10 | Joe Derp | Programmer |
11 | Jon Herpaderp | Animator |
12 | Joblot O’Stuff | Tester |
13 | Joderp Herpderpenson | Artist |
14 | Jo McQueryfiller | Project Manager |
Get Projects with no Project Manager.
Get list of Project Managers from Team_Member table.
SELECT * FROM Team_Member WHERE Role_id = 1;
data_format.function(query10b_part1,
"Select Team Members who are Project Managers",
"query", "#FF0000")
Id | First_Name | Last_Name | Role_Id | |
---|---|---|---|---|
2 | Derp | McDerp | derpmcderp@daie.ca4 | 1 |
14 | Jo | McQueryfiller | j.mcqueryfiller@daie.ca4 | 1 |
List of Project managers and the projects assigned to them. Joins
Team_Member, Project_Team and Role tables.
SELECT First_Name || ' ' || Last_Name as "Member Name",
r.name AS "Role", r.Id AS "Role ID", pt.Project_Id AS "Project ID"
FROM Team_Member tm
INNER JOIN Project_Team pt
ON pt.Team_Member_Id = tm.Id
INNER JOIN Role r
ON tm.Role_Id = r.Id
WHERE tm.Role_Id IN
(SELECT Role_Id FROM Team_Member WHERE Role_id = 1);
data_format.function(query10b_part2,
"Project Managers assigned projects using Inner Join",
"query", "#FF0000")
Member Name | Role | Role ID | Project ID |
---|---|---|---|
Derp McDerp | Project Manager | 1 | 1 |
Derp McDerp | Project Manager | 1 | 2 |
Derp McDerp | Project Manager | 1 | 3 |
Jo McQueryfiller | Project Manager | 1 | 4 |
Jo McQueryfiller | Project Manager | 1 | 6 |
Jo McQueryfiller | Project Manager | 1 | 7 |
List of projects with no manager assigned. Joins Project, Team_Member
and Role tables.
Select p.Id AS "Project Id", p.Name AS "Projects Name"
FROM Project p
WHERE p.Id NOT IN
(SELECT DISTINCT pt.Project_Id
FROM Team_Member tm
INNER JOIN Project_Team pt
ON pt.Team_Member_Id = tm.Id
INNER JOIN Role r
ON tm.Role_Id = r.Id
WHERE tm.Role_Id IN
(SELECT Role_Id FROM Team_Member WHERE Role_id = 1));
data_format.function(query10b_part3,
"List of Projects with no Project Manager assigned",
"query", "#FF0000")
Project Id | Projects Name |
---|---|
5 | Christmas 2022 Project |
8 | Project Filler |
9 | Derp Project |
10 | Hmmm I Ran Out of Names |
Nested select query
Select the work items that are at least in Review (Review, or Done),
i.e.with a status greater than 2.
SELECT * FROM Work_Item WHERE Status_Id > 2
data_format.function(query11_subquery_part_1,
"Get Work Items that are at least In Review",
"query", "#FF0000") # format query
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
2 | Art Test Thingy | 3 | 3 |
4 | Art Concept Thingy | 4 | 7 |
5 | Art Shading Thingy | 4 | 8 |
10 | Blueprint Test | 3 | 2 |
12 | Query Model Thingy | 3 | 11 |
13 | Another Test | 4 | 13 |
Select work items that contain the string “test”.
SELECT * FROM Work_Item WHERE Name LIKE "%test%"
data_format.function(query12_subquery_part_2, "Work Items with string 'test'",
"query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
2 | Art Test Thingy | 3 | 3 |
7 | 3D Model Test Obj | 2 | 3 |
10 | Blueprint Test | 3 | 2 |
11 | Art Test | 1 | 12 |
13 | Another Test | 4 | 13 |
Select work items that contain the string “test” and have a Status_Id
greater than 2.
SELECT * FROM Work_Item
WHERE Name LIKE "%test%"
AND Status_Id IN
(SELECT Status_Id FROM Work_Item
WHERE Status_Id > 2)
data_format.function(query13_subquery_with_select,
"Test Work Items that are in review or done", "query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
2 | Art Test Thingy | 3 | 3 |
10 | Blueprint Test | 3 | 2 |
13 | Another Test | 4 | 13 |
Select work items that contain the string “test” and have a Status_Id less than 3.
SELECT * FROM Work_Item
WHERE Name LIKE "%test%"
AND Status_Id NOT IN
(SELECT Status_Id FROM Work_Item
WHERE Status_Id > 2)
data_format.function(query13b_subquery_with_select_not_in,
"Test Work Items in To Do or In Progress", "query", "#FF0000")
Id | Name | Status_Id | Assigned_To |
---|---|---|---|
7 | 3D Model Test Obj | 2 | 3 |
11 | Art Test | 1 | 12 |
Select delivery dates from Project table to compare query against. And order them to make it that much easier to find.
SELECT Delivery_Date AS "Project Due Dates" FROM Project
ORDER BY Delivery_Date
data_format.function(query14_check_dates,
"Ordered Project Due Dates",
"query", "#FF0000") # Format query data
Project Due Dates |
---|
2022-12-14 |
2022-12-25 |
2023-01-11 |
2023-01-17 |
2023-01-20 |
2023-01-20 |
2023-01-24 |
2023-02-01 |
2023-03-01 |
2023-03-17 |
Select projects with a delivery date in the range 16/01/2023 to 25/01/2023.
SELECT * FROM Project
WHERE Delivery_Date
BETWEEN "2023-01-16" AND "2023-01-25";
data_format.function(query15_select_across_date_range,
"Project Due between 16th and 25th of January 2023",
"query", "#FF0000")
Id | Name | Delivery_Date |
---|---|---|
2 | DAIE CA4 | 2023-01-20 |
3 | New Project | 2023-01-24 |
6 | Date Range Project | 2023-01-17 |
10 | Hmmm I Ran Out of Names | 2023-01-20 |
dbDisconnect(conn)