Example: employees database schema
Schema
The employees database (schema.sql) contain five base tables male(emp_name, birth_date), female(emp_name, birth_date), others(emp_name, birth_date, gender), ed(emp_name, dept_name) and eed(emp_name, dept_name).
Table male contains information about male people
| emp_name | birth_date |
|---|---|
| Chirstian Koblick | 1954-05-01 |
| Georgi Facello | 1953-09-02 |
| Kyoichi Maliniak | 1955-01-21 |
| Parto Bamford | 1959-12-03 |
| Saniya Kalloufi | 1958-02-19 |
Table female contains information about female people
| emp_name | birth_date |
|---|---|
| Anneke Preusig | 1953-04-20 |
| Bezalel Simmel | 1964-06-02 |
| Duangkaew Piveteau | 1963-06-01 |
| Sumant Peac | 1952-04-19 |
| Tzvetan Zielinski | 1957-05-23 |
Table others contains information of people having other genders
| emp_name | birth_date | gender |
|---|---|---|
Table ed has all historical departments of each person
| emp_name | dept_name |
|---|---|
| Anneke Preusig | Development |
| Bezalel Simmel | Sales |
| Chirstian Koblick | Production |
| Duangkaew Piveteau | Production |
| Duangkaew Piveteau | Quality Management |
| Georgi Facello | Development |
| Kyoichi Maliniak | Human Resources |
| Parto Bamford | Production |
| Saniya Kalloufi | Development |
| Sumant Peac | Quality Management |
| Tzvetan Zielinski | Research |
Table eed contains only former departments of each person
| emp_name | dept_name |
|---|---|
| Duangkaew Piveteau | Production |
| Saniya Kalloufi | Development |
Several views are expected to be created including residents(emp_name, birth_date, gender), ced(emp_name, dept_name),
residents1962(emp_name, birth_date, gender), employees(emp_name, birth_date, gender), researchers(emp_name) and retired(emp_name).
Update strategy for residents
The view residents contains all personal information:
| emp_name | birth_date | gender |
|---|---|---|
| Kyoichi Maliniak | 1955-01-21 | M |
| Saniya Kalloufi | 1958-02-19 | M |
| Parto Bamford | 1959-12-03 | M |
| Georgi Facello | 1953-09-02 | M |
| Tzvetan Zielinski | 1957-05-23 | F |
| Bezalel Simmel | 1964-06-02 | F |
| Anneke Preusig | 1953-04-20 | F |
| Duangkaew Piveteau | 1963-06-01 | F |
| Sumant Peac | 1952-04-19 | F |
| Chirstian Koblick | 1954-05-01 | M |
For the view residents, we use the attribute GENDER to choose relevant base tables for propagating updated tuples in residents. More concretely, if there is
a person in residents but not in any of the source tables male,
female and other, we insert this person into the table corresponding
to his/her GENDER. In contrast, we delete from the source tables the
people, who do not appear in the view anymore. The Datalog putback
program for residents is the following (residents.dl):
source male('EMP_NAME':string, 'BIRTH_DATE':string).
source female('EMP_NAME':string, 'BIRTH_DATE':string).
source others('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
view residents('EMP_NAME':string,'BIRTH_DATE':string,'GENDER':string).
+male(E, B) :- residents(E, B, G), G = 'M', not male(E, B), not others(E, B, G).
-male(E, B) :- male(E, B), G = 'M', not residents(E, B, G).
+female(E, B) :- residents(E, B, G), G = 'F', not female(E, B), not others(E, B, G).
-female(E, B) :- female(E, B), G = 'F', not residents(E, B, G).
+others(E, B, G) :- residents(E, B, G), not G = 'M', not G = 'F', not others(E, B, G).
-others(E, B, G) :- others(E, B, G), not residents(E, B, G).
Verifying and compiling the update strategy into SQL:

Let’s try an insertion to the view residents:
insert into residents values ('A', '2000-01-02', 'F');
The insertion will be propagated to the table female:

Update strategy for ced
The view ced contains information about the current departments of
each employee.
| emp_name | dept_name |
|---|---|
| Chirstian Koblick | Production |
| Duangkaew Piveteau | Quality Management |
| Parto Bamford | Production |
| Sumant Peac | Quality Management |
| Bezalel Simmel | Sales |
| Tzvetan Zielinski | Research |
| Kyoichi Maliniak | Human Resources |
| Anneke Preusig | Development |
| Georgi Facello | Development |
We express the following update strategy for propagating
updated data in this view to the base tables ed and eed. If a person
is in a department according to ed but he/she is currently not in this
department anymore according to ced, this department becomes his/her
previous department, thus need to be added to eed. If a person used to
be in a department according to eed, but he/she come back to this
department according to ced, then this department of him/her need to be removed
from eed. The update strategy program is as follows (ced.dl):
source ed('EMP_NAME':string,'DEPT_NAME':string).
source eed('EMP_NAME':string,'DEPT_NAME':string).
view ced('EMP_NAME':string, 'DEPT_NAME':string).
+ed(E, D) :- ced(E, D), NOT ed(E, D).
-eed(E, D) :- ced(E, D), eed(E, D).
+eed(E, D) :- ed(E, D), NOT ced(E, D), NOT eed(E, D).
Verifying and compiling the update strategy into SQL:

Let’s try an update to ced:
update ced set dept_name = 'Research' where emp_name='Anneke Preusig';
Meaning that Anneke Preusig changes her department to Research. This movement is reflected to the source tables:

Update strategy for residents1962
The view residents1962 contains all residents having a birth date in 1962.
| emp_name | birth_date | gender |
|---|---|---|
We define constraints to ensure that in the updated view residents1962
there is no tuple having a value of the attribute BIRTH_DATE not in
1962. Any view updates violating these constraints are rejected.
Interestingly, by having the updatable view residents, we now can use residents as the source table of the view residents1962 and write an update strategy more easily.
By this way, our update strategy is to insert into the source table residents
any new tuples appearing in residents1962 but not yet in residents.
On the other hand, we delete only tuples in residents having
BIRTH_DATE in 1962, if they do not appear in residents1962 anymore.
The strategy is as follows (residents1962.dl):
source residents('EMP_NAME':string,'BIRTH_DATE':string,'GENDER':string).
view residents1962('EMP_NAME':string,'BIRTH_DATE':string,'GENDER':string).
_|_ :- residents1962(E,B,G), B > '1962-12-31'.
_|_ :- residents1962(E,B,G), B < '1962-01-01'.
+residents(E,B,G) :- residents1962(E,B,G), ¬ residents(E,B,G).
-residents(E,B,G) :- residents(E,B,G), B >= '1962-01-01', B <= '1962-12-31', ¬ residents1962(E,B,G).
Verifying and compiling the update strategy into SQL:

Let’s try an update to residents1962:
INSERT INTO public.residents1962 (emp_name, birth_date, gender) VALUES('new resident 3', '1962-01-01', 'M');

The generated SQL also has a fragment of code that checks whether the defined constraints on the view are satisfied when having view updates. Let’s try to insert a resident not born in 1962 to the view:

The insertion is rejected with error message ‘Invalid view update: constraints on the view are violated’
Update strategy for employees
The view employees contains residents, who are underemployment
| emp_name | birth_date | gender |
|---|---|---|
| Anneke Preusig | 1953-04-20 | F |
| Bezalel Simmel | 1964-06-02 | F |
| Chirstian Koblick | 1954-05-01 | M |
| Duangkaew Piveteau | 1963-06-01 | F |
| Georgi Facello | 1953-09-02 | M |
| Kyoichi Maliniak | 1955-01-21 | M |
| Parto Bamford | 1959-12-03 | M |
| Sumant Peac | 1952-04-19 | F |
| Tzvetan Zielinski | 1957-05-23 | F |
For these views, we use the two views residents and ced defined before as the
source relations. This is possible because both residents and ced
are all updatable, thus they can be treated as base tables.
More interestingly, by using constraints, we can specify more
complicated restrictions of updates on these views. As an example, we
define a constraint on the view residents by the following Datalog
rule: ⊥ :- employees(E,B,G), ¬ ced(E,_). That means there is no
tuple ⟨E,B,G⟩ in the updated view employees having the value E of
the attribute EMP_NAME, which cannot be found in any tuples of ced.
By the constraint, we do not allow inserting into employees a really
new employee, who is not mentioned in the source relation ced. The following is the update strategy for employees (employees.dl):
source residents('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
source ced('EMP_NAME':string, 'DEPT_NAME':string).
view employees('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
% constraint
_|_ :- employees(E,B,G), ¬ced(E,_).
% update strategy
+residents(E,B,G) :- employees(E,B,G), ¬residents(E,B,G).
-residents(E,B,G) :- residents(E,B,G), ced(E,_), ¬employees(E,B,G).
Verifying and compiling the update strategy into SQL:

Let’s try updating the birth date of an employee:
UPDATE employees SET birth_date='1953-04-21' WHERE emp_name='Anneke Preusig'
The source tables will be updated:

Update strategy for researchers
The view researchers shows only employees, who are doing research.
| emp_name |
|---|
| Tzvetan Zielinski |
For this view, an update strategy is as the following researchers.dl:
source residents('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
source ced('EMP_NAME':string, 'DEPT_NAME':string).
view researchers('EMP_NAME':string).
-ced(E,D) :- residents(E,B,G), ced(E,D), D = 'Research', ¬researchers(E).
+residents(E,B,G) :- researchers(E), ¬residents(E,_,_), B='0001-01-01', G='unknown'.
+ced(E,D) :- researchers(E), D = 'Research'.
The first two rules mean if a resident is a researcher but not in the view researchers anymore, we deleted the current department Research of this resident.
By contrast, by the third rule, if a new researcher appears in the view, we need to put this department information to the table ced, which contains information about the current departments.
The second rule ensures each researcher is a resident by inserting into residents if a researcher is not yet a resident.
Verifying and compiling the update strategy into SQL:

Let’s try to remove a researcher:
DELETE FROM researchers WHERE emp_name='Anneke Preusig';
And Anneke Preusig will no longer belong to the department Research

Update strategy for retired
The view retired contains residents, who were retired.
| emp_name |
|---|
| Saniya Kalloufi |
The update strategy for retired is to remove from the ced the current departments of people, who are retired (in the view retired), and to insert a new department for each resident, who is not retired but is not yet mentioned in ced. We also ensure a retired person is a resident as follows (retired.dl):
source residents('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
source ced('EMP_NAME':string, 'DEPT_NAME':string).
view retired('EMP_NAME':string).
-ced(E,D) :- ced(E,D), retired(E).
+residents(E,B,G) :- retired(E), ¬ residents(E,_,_), B='0001-01-01', G='unknown'.
+ced(E,D) :- residents(E,_,_), ¬retired(E), ¬ced(E,_) , D='unknown'.
Verifying and compiling the update strategy into SQL:

For example, if Parto Bamford is now retired:
insert into retired values('Parto Bamford');
He will not be in any department anymore:

Update strategy for voter
Let blacklist(EMP_NAME) be a blacklist of residents
| emp_name |
|---|
| Kyoichi Maliniak |
We now define an update strategy for a view voter(emp_name, birth_date) containing residents, who have the right to vote at elections, as follows (voter.dl):
source blacklist('EMP_NAME':string).
source residents('EMP_NAME':string, 'BIRTH_DATE':string, 'GENDER':string).
view voter('EMP_NAME':string, 'BIRTH_DATE':string).
⊥ :- voter(NAME,BIRTH_DATE), blacklist(NAME).
+residents(E,B,G) :- voter(E,B), G='unknown', ¬ residents(E,B,_).
-residents(E,B,G) :- residents(E,B,G), not blacklist(E), ¬ voter(E,B).
The constraint ⊥ :- voter(NAME,BIRTH_DATE), blacklist(NAME). ensures that no person in the blacklist can be inserted to the view voter. Updated data in the view voter is reflected to the source relation residents by the last two rules.
Verifying and compiling the update strategy into SQL:

If there is an attempt to insert Kyoichi Maliniak into voter:
INSERT INTO voter values('Kyoichi Maliniak', '1955-01-21');
The attempt will be rejected:
