Code
library(DBI)
<- dbConnect(RSQLite::SQLite(), "mfa.db") # establish SQLite connection to the database con
In this project, we will explore the concepts of soft deletions, views, and triggers in the context of the Museum of Fine Arts (MFA). The MFA is a century-old museum housing numerous historical and contemporary artifacts and artworks. It manages its extensive collection through the MFA database, which tracks thousands of items. However, for the purpose of this project, we will work with a subset of the database containing only ten items in the collections
table.
The Schema of the MFA database is shown above. The collections
table contains the following columns:
id
, which is the ID of the table that serves as the primary keytitle
, which is the name of the art pieceaccession_number
, which is a unique ID used by the museum internallyacquired
, which indicates when the art was acquiredLet us now establish the SQLite connection to the database using DBI package.
The data of the collections
table is as follows:
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 |
3 | Spring outing | 14.76 | 1914-01-08 |
4 | Imaginative landscape | 56.496 | NA |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
6 | Tile Lunette | 06.2437 | 1906-11-08 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
8 | Country road with culvert | 76.431 | NA |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
Imagine you are a database administrator of the MFA and solve the following problems:
Implement a soft deletion of items in the collections
table, where a log of sold artworks is kept in the column named “deleted” instead of completely removing them from the table, so that the records of artworks in the collection are not lost. The “deleted” column in the collections
table must have a value of 0 for the available items for sale and a value of 1 for the items that have been sold. Imagine the artworks “Farmers Working at Dawn” and “Tile Lunette” were sold, and implement this idea of soft deletion on them.
Create a view named current_collections
using all the columns of the collections table except the “deleted” column, so that the view can be used to display only the information about the artworks that are available for sale.
Since data in the view cannot be modified directly, create a trigger on the current_collections
view that soft deletes the data from the underlying collections
table, as per the idea of soft deletion discussed above. The trigger must be activated when any data is attempted to be deleted from the view. Demonstrate this trigger by selling all the artworks that have no acquired date.
Imagine the items sold in the task 3 are rebought. Now, create a trigger on the current_collections
view that reverses the soft deletion, i.e., setting the corresponding row’s deleted value to 0 in the underlying collections
table to indicate that the items are again available. The trigger must be executed when any soft-deleted data is attempted to be inserted into the current_collections
view.
Create a trigger on the current_collections
view that inserts new data into the underlying collections
table when any new data is attempted to be inserted into the view. Demonstrate this trigger by buying new artworks ‘Adoration of the Magi’ (accession_number: 1971.71, acquired: 2022-01-11) and ‘Agony in the Garden’ (accession_number: 68.206, acquired: 2022-05-01).
First, let’s query the collections
table.
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 |
3 | Spring outing | 14.76 | 1914-01-08 |
4 | Imaginative landscape | 56.496 | NA |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
6 | Tile Lunette | 06.2437 | 1906-11-08 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
8 | Country road with culvert | 76.431 | NA |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
We can see that the collections
table does not have a “deleted” column yet to implement soft deletion, so we need to add it first. The default value 0 indicates that the item is available for sale.
We can verify that this worked by querying the collections
table.
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 0 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 0 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 0 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 0 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
Now, let us perform a soft delete on the artworks “Farmers working at dawn” and “Tile Lunette” by updating their “deleted” column to 1.
We can verify that this worked by querying the collections
table to check for soft deletion.
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 0 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 0 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
We will create a view named current_collections
to display only the items that are available for sale by selecting the rows with a “deleted” column value of 0 from the collections
table.
We will query the current_collections
view to verify that artworks “Farmers working at dawn” and “Tile Lunette”, which were soft deleted, are not present.
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
3 | Spring outing | 14.76 | 1914-01-08 |
4 | Imaginative landscape | 56.496 | NA |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
8 | Country road with culvert | 76.431 | NA |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
Every time we attempt to delete rows from the current_collections
view, the trigger named delete
below will instead update the “deleted” column of the row to 1 in the underlying collections
table, thus completing the soft deletion.
We use the keyword OLD within our UPDATE clause to indicate that the ID of the row updated in collections
table should be the same as the ID of the row we are trying to delete from the current_collections
view.
let’s query the current_collections
view first to have an idea of which items have no acquired date before implementing the trigger.
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
3 | Spring outing | 14.76 | 1914-01-08 |
4 | Imaginative landscape | 56.496 | NA |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
8 | Country road with culvert | 76.431 | NA |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
We notice that ‘Imaginative Landscape’ and ‘Country Road with Culvert’ do not have acquired date. Now, we will delete the artworks that have no acquired date from the current_collections
view to activate the trigger.
We can verify that this worked by querying the current_collections
view and collections
table to check for soft deletion.
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
3 | Spring outing | 14.76 | 1914-01-08 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 1 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 1 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
We will create a trigger named insert_when_exists
to handle the situation where we try to insert a row into a view that already exists in the underlying table but was soft deleted.
The WHEN
keyword is used to check if the “accession number” of the artwork already exists in the collections
table. This works because an “accession number” uniquely identifies every piece of art in this table. If the artwork does exist in the underlying table, we set its “deleted” value to 0, indicating a reversal of the soft deletion.
Before using trigger, we can see that the values in the “deleted” column for ‘Imaginative Landscape’ and ‘Country Road with Culvert’ are 1, indicating that they were sold.
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 1 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 1 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
Now, let’s rebuy the artworks ‘Imaginative landscape’ (accession_number: 56.496, acquired: NULL) and ‘Country road with culvert’(accession_number: 76.431, acquired: NULL) and execute the trigger.
We can verify that this worked by checking whether the “deleted” column values of ‘Imaginative landscape’ and ‘Country road with culvert’ are switched back to 0 from 1 in the collections
table.
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 0 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 0 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
We will create a trigger named insert_when_new
to handle the situation where we try to insert a row into a view that does not exist in the underlying table.
When the “accession number” of the inserted data is not already present within collections
table, it inserts the row into the table.
CREATE TRIGGER "insert_when_new"
INSTEAD OF INSERT ON "current_collections"
FOR EACH ROW
WHEN NEW."accession_number" NOT IN (
SELECT "accession_number" FROM "collections"
)
BEGIN
INSERT INTO "collections" ("title", "accession_number", "acquired")
VALUES (NEW."title", NEW."accession_number", NEW."acquired");
END;
Before executing this trigger, let’s query the collections
table to see what items are present.
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 0 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 0 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |
Now, let’s execute the trigger by inserting newly bought artworks ‘Adoration of the Magi’ (accession_number: 1971.71, acquired: 2022-01-11) and ‘Agony in the Garden’ (accession_number: 68.206, acquired: 2022-05-01).
We can verify that this worked by querying the current_collections
view and collections
table to check for insertion.
id | title | accession_number | acquired |
---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 |
3 | Spring outing | 14.76 | 1914-01-08 |
4 | Imaginative landscape | 56.496 | NA |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 |
8 | Country road with culvert | 76.431 | NA |
9 | Family of acrobats | 1974.352 | 1933-03-30 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 |
11 | Adoration of the Magi | 1971.71 | 2022-01-11 |
12 | Agony in the Garden | 68.206 | 2022-05-01 |
id | title | accession_number | acquired | deleted |
---|---|---|---|---|
1 | Profusion of flowers | 56.257 | 1956-04-12 | 0 |
2 | Farmers working at dawn | 11.6152 | 1911-08-03 | 1 |
3 | Spring outing | 14.76 | 1914-01-08 | 0 |
4 | Imaginative landscape | 56.496 | NA | 0 |
5 | Peonies and butterfly | 06.1899 | 1906-01-01 | 0 |
6 | Tile Lunette | 06.2437 | 1906-11-08 | 1 |
7 | Statuette of a shrew | 01.105 | 1901-02-11 | 0 |
8 | Country road with culvert | 76.431 | NA | 0 |
9 | Family of acrobats | 1974.352 | 1933-03-30 | 0 |
10 | Bacchic scene with minotaur | 1974.379 | 1933-05-18 | 0 |