COMP3311 24T2 |
Assignment 1 Queries and Functions on RugDB |
Database Systems |
[Assignment Spec] [Database Design] [Examples] [Testing]
This assignment aims to give you practice in
The goal is to build some useful data access operations on the RugDB database,
which contains a wealth of information about Persian rugs.
One aim of this assignment is to use SQL queries (packaged as views) to extract such information.
Another is to build PlpgSQL functions that can support higher-level activities,
such as might be needed in a Web interface.
Submission: | Login to Course Web Site > Assignments
> Assignment 1 > [Submit] > upload ass1.sql or, on a CSE server, give cs3311 ass1 ass1.sql |
Required Files: | ass1.sql (contains both SQL views and PLpgSQL functions) |
Deadline: | 21:59:59 Friday 28th June 2024 |
Marks: | 13 marks toward your total mark for this course |
Late Penalty: | 0.2 marks off the achieved mark for each hour late, for 5 days any submission after 5 days scores 0 marks ... UNSW late penalty policy |
How to do this assignment:
Details of the above steps are given below. Note that you can put the files wherever you like; they do not have to be under your /localstorage directory. You should edit your SQL files on hosts other than vxdb2. The only time that you need to use vxdb2 is to manipulate your database. Since you can work at home machine, you don't have to use vxdb2 at all while developing your solution, but you should definitely test it there before submitting.
In the Western world, Persia was historically the common name for Iran. Thus, the term "Persian rug" refers to rugs made in the region now known as Iran. However, Persia represents more than just a country; it is a rich and diverse culture. The patterns and styles of Persian rugs reflect different aspects of Persian history, serving not only as beautiful works of art but also as visual narratives of the region's heritage.
Persian rugs are meticulously crafted by skilled artisans over several months or even years, depending on the size of the rug. Each rug is composed of thousands of intricate knots, with each region of Iran boasting its own distinct styles and patterns. The colours, designs, and knotting techniques employed in these rugs represent the unique histories, artistic traditions, and cultural identities of the people from various areas of the country.
Photo from:
In order to work with a database, it is useful to have some background in the domain of data being stored. Here is a very quick tour of Persian Rugs. If you want to know more, see the Wikipedia page on Persian Rugs.
To build a database on rugs, we need to consider:
Specific properties that we want to consider:
The schema is described in more detail both as an ER model and an SQL schema in the schema page.
The following sections describe how to carry out this assignment.
Some of the instructions must be followed exactly; others require
you to exercise some discretion. The instructions are targetted at
people doing the assignment on vxdb2. If you plan to work
on this
assignment at home on your own computer, you'll need to adapt the
instructions to local conditions
.
If you're doing your assignment on the CSE machines, some commands must be carried out on vxdb2, while others can (and probably should) be done on a CSE machine other than vxdb2. In the examples below, we'll use vxdb2 to indicate that the comand must be done on vxdb2 and cse$ to indicate that it can be done elsewhere.
The first step in setting up this assignment is to set up a directory to hold your files for this assignment.
cse$ mkdir /my/dir/for/ass1 cse$ cd /my/dir/for/ass1 cse$ cp /home/cs3311/web/24T2/assignments/ass1/ass1.sql ass1.sql cse$ ln -s /home/cs3311/web/24T2/assignments/ass1/ass1.dump ass1.dump
This gives you a template for the SQL views and SQL and PLpgSQL functions that you need to submit. You edit this file, (re)load the definitions into the database you created for the assignment, and test it there.
As supplied, the ass1.sql template file consists entirely of comments; remove the comments from whatever question you're working on. This allows you to load the ass1.sql file without getting syntax errors from the not-yet-completed parts of the template. Of course, don't forget to remove the comments from all completed questions before testing and submitting.
The next step is to set up your database:
... login to vxdb2, source env, run your server as usual ... ... if you already had such a database vxdb$ dropdb ass1 ... create a new empty atabase vxdb$ createdb ass1 ... load the database, saving the output in a file called log vxdb$ psql ass1 -f ass1.dump ... examine the database contents vxdb$ psql ass1
The database loading should take less than 2 seconds on vxdb2, and will produce messages like:
CREATE DOMAIN CREATE TYPE SET CREATE TABLE COPY number ALTER TABLE
The ass1.dump file contains the schema and data in a single file, along with a simple PLpgSQL function (dbpop()), which counts the number of tuples in each table.
If you're running PostgreSQL at home you can download the dump file here: ass1.dump.
Think of some questions you could ask on the database (e.g. like the ones in the lectures) and work out SQL queries to answer them.
One useful query is
ass1=# select * from dbpop();
This will give you a list of tables and the number of tuples in each. The dbpop() function is written in PLpgSQL, and makes use of the PostgreSQL catalog. We'll look at this later in the term.
Answer each of the following questions by typing SQL or PLpgSQL into the ass1.sql file. You may find it convenient to work on each question in a temporary file, so that you don't have to keep loading all of the other views and functions each time you change the one you're working on. Note that you can add as many auxuliary views and functions to ass1.sql as you want. However, make sure that everything that's required to make all of your views and functions work is in the ass1.sql file before you submit.
Note #1: many of the queries are phrased in the singular e.g. "Find the rug that ...". Despite the use of "rug" (singular), it is possible that multiple rugs satisfy the query. If this is the case you should return all rugs that satisfy the query. Because of this you should not use LIMIT 1.
Note #2: the database is not a complete picture of rugs in the Real World. Treat each question as being prefaced by "According to the RugDB database ...".
Note #3: you can assume that the names for styles and factories are unique; you cannot assume this for rug names.
Note #4: do not worry about the order of tuples in your result; we will apply order by when testing the queries (see the ordering in the Examples page).
There are examples of the results of each view and function in the Examples page.
Style mark
Given that you've already taken multiple programming courses, we should be able to assume that you'll express your code with good style conventions. But, just in case ...
You must ensure that your SQL queries follow a consistent style. The one I've been using in the lectures is fine. An alternative, where the word JOIN comes at the start of the line, is also OK. The main thing is to choose one style and use it consistently.
Similarly, PLpgSQL should be laid out like you would lay out any procedural programming language. E.g. bodies of loops should be indented from the FOR or WHILE statement that introduces them. E.g. the body of a function should be indented from the BEGIN...END.
Ugly, inconsistent layout of SQL queries and PLpgSQL functions will be penalised.
Write a view Q1(province, nfactories) that returns a list of all provinces and the number of factories in each province.
The columns in the result are:
Write a view Q2(style, knot_length_diff) that determines which style(s) have the largest difference between their minimum and maximum knot lengths.
The columns in the result are:
Write a view Q3(style, lo_knot_length, hi_knot_length, min_knot_length, max_knot_length) that gives a list of rug styles satisfying the properties:
Write a view Q4(factory, rating) that returns the factory (or factories) with the maximum average rating for all their rugs.
The columns in the result are:
To avoid factories with a single high-rated rug coming out on top, we only consider factories that have at least five rated rug. If rugs are crafted collaboratively, give the rating to both the factories involved. Make sure that you compute the average rating using floating point numbers; if you use integers, PostgreSQL truncates to an integer like C does. Don't include rugs with no rating (i.e. rugs.rating is NULL).
The rating value should be returned as numeric(3,1).
One of the most important characteristic of a rug is the density of its knots.
One way to represent this is through knot per feet.
To measure it, experts use a simple technique.
They take a 1-foot long ruler and place it on the back of the rug.
Then, they count the total number of knots within that 1-foot length.
They only count the knots in a 1-foot length and not the total knot in a square feet.
Remember, the size
of the rug that is given to you is in square feet,
(ft^2) while the total knots measure is in feet (ft).
If you want to calculate the total number of knots in a rug, you have to:
Total number of knots = knot_per_foot x knot_per_foot x size
You will notice that many rugs do not have knot per feet value in the database and its value is null.
Unfortunately this can happen in real world.
If you find a rug which knot per feet is not given, you need to use the average industry value which is 50.
Write an SQL function Q5(pattern text)
whose argument is a pattern (regex) representing part of a rug name.
The function returns a set of 0 or more tuples for any rugs whose name matches the pattern (regex),
and with the following fields:
You must define the function as follows:
Q5(pattern text) returns table(rug text, size_and_stoper text, total_knots numeric)
The total knots value is of type numeric(8,0).
You will need to determine how to construct the size_and_stoper string.
Write an SQL function Q6(pattern text)
whose argument is a string representing part of a province name.
The function returns a set of 0 or more tuples for any provinces whose name contains the pattern as a substring (case-insensitive) (not a regex),
and with the following fields:
Q6(pattern text) returns table(province text, first integer, nrugs integer, rating numeric)
The rating value should be cast to type numeric(3,1) within the function.
Write a PLpgSQL function Q7(_rugID integer) whose argument is an integer representing a rug ID (Rugs.id) value. The function returns a single text string, formatted as follows:
No such rug (<_rugID>)
"<Name of rug>"
"<Name of rug>" no materials recordedNote that there are exactly two spaces before the no materials.
"<Name of rug>" contains: <material 1 name> (<material 1 type>) <material 2 name> (<material 2 type>)
Note that the return value of this function is a single text string.
It will likely contain embedded newline characters, but there should be no trailing newline character.
There are examples of the return values in the Examples page, in case the above is not clear enough.
Note also that, in its output, psql uses a plus + symbol to indicate that there is an embedded newline.
The plus symbol is simply an artifact of the way psql displays strings.
Do not embed plus symbols into your return string.
Write a PLpgSQL function Q8(pattern text) whose argument is a string representing part of a rug name. The function returns a set of 0 or more tuples for any rugs whose name contains the pattern (case-insensitive matching), and with the following fields:
If the rug is a collaboration rug (crafted_by more than one factory), the names of all factories involved must be included, separated by '+' characters, and appear in alphabetical order of the factory names.
The names of the piles in the list of piles contained in the rug must be separated by ',' characters, and must appear in alphabetical order.
If a rug has no pile ingredients recorded, then the piles string should be set to:
no piles recorded
The function needs to be defined differently to the functions above that returned table(...). For this function, we need to define a new tuple type and have the function return a setof tuples of that type:
drop type if exists RugPiles cascade; create type RugPiles as (rug text, factory text, piles text);
The drop type statement is included so that you can reload the ass1.sql file multiple times without generating errors. It does, however, generate a NOTICE, which looks like an error, but is actually harmless.
Q8(pattern text) returns setof RugPiles
Write a PLpgSQL function Q9(factoryID integer) whose argument is an integer, possibly containing a Factory.id value. The function returns a set of Collab tuples (see below) for the factory, and with the following fields:
There are a number of different cases for what appears in the Collab tuples:
The function needs to be defined differently to the functions above that returned table(...). For this function, we need to define a new tuple type and have the function return a setof tuples of that type:
drop type if exists Collab cascade; create type Collab as (factory text, collaborator text);
The drop type statement is included so that you can reload the ass1.sql file multiple times without generating errors. It does, however, generate a NOTICE, which looks like an error, but is actually harmless.
Q9(factoryID integer) returns setof Collab
Note that the function always returns at least one tuple, even if factoryID is not valid.
Note also that this is different to question Q6, where the list of list of materials was formed by string concatenation;
in this case, each collaborating factory is in a separate tuple.
In case the above description is not clear, there are many examples in the Example page.
We will test your submission as follows:
ass1.dump
psql TestingDB -f ass1.sql
(using your ass1.sql)
psql TestingDB -f ass1.sql
(using your ass1.sql)
Note that there is a time-limit on the execution of queries. If any query takes longer than 3 seconds to run (you can check this using the \timing flag) your mark for that query will be reduced.
Your submitted code must be complete so that when we do the above, your ass1.sql will load without errors. If your code does not work when installed for testing as described above and the reason for the failure is that your ass1.sql did not contain all of the required definitions, you will be penalised by a 2 mark penalty. If you code does not load because your definitions are in the wrong order, there will be a 1 mark penalty.
Before you submit, it would be useful to test whether the files you submit will work on vxdb2, by doing the following:
vxdb2$ dropdb ass1 vxdb2$ createdb ass1 vxdb2$ psql ass1 -f ass1.dump vxdb2$ psql ass1 -f ass1.sql
These commands may produce information messages, but they should not produce any errors.
Dear students, we value transparency and strive to ensure a clear understanding of our responsibilities and expectations. In this regard, we would like to outline some of our responsibilities to you:
Assignment Release and MarkingTo ensure a fair and productive learning experience, we kindly request that you:
Have fun, Armin