3

I have designed a schema and generated a few SQL queries. I'm using PostgreSQL.

For example:

CREATE TABLE train 
(
  train_code SERIAL PRIMARY KEY,
  name TEXT NOT NULL
); 

CREATE TABLE journey 
(
  journey_id SERIAL PRIMARY KEY, 
  int INTEGER,
  train_code REFERENCES train(train_code)
); 

CREATE TABLE price 
(
  journey_id REFERENCES journey(journey_id),
  price INTEGER
); 

Give me all train names that commence from train_code NYC or SFO that are priced $50 or more. (assume the price table is in $ already).

SELECT train.name
JOIN   train
JOIN   journey on train.train_code = journey.train_code
JOIN   price on price.journey_id = journey.journey_id 
WHERE  price.price >= 50 
AND    journey.train_code IN ('NYC', 'SFO') 
AND    journey.int = 1 -- (first train of the journey)

I am unsure how to convert this into a relational algebra and/or calculus query. I have looked at a few converters e.g. http://dbis-uibk.github.io/relax/calc.htm but in this calculator 'join' for example and 'in' is not allowed.

2

You have a number of "mistakes" in your SQL, that should be addressed before you translate it to relational algebra.

  1. You don't have a FROM in your SQL. You shouldn't start by JOINing.
  2. You seem to assume that train_code is a text, yet you define it as an integer.
  3. Your table definitions don't define a type for train_code in the journey table, nor for journey_id in the price one.
  4. The tool you're using doesn't understand SERIAL (which is not standard SQL). Just don't use it. Use INTEGER instead.

So, your table definitions just should be:

CREATE TABLE train 
(
  train_code TEXT PRIMARY KEY,
  name TEXT NOT NULL
); 

CREATE TABLE journey 
(
  journey_id INTEGER PRIMARY KEY, 
  int INTEGER,
  train_code TEXT REFERENCES train (train_code)
); 

CREATE TABLE price 
(
  journey_id INTEGER REFERENCES journey (journey_id),
  price INTEGER
); 

This is translated by RelaX to:

group: joanolo (imported from SQL)

train = {
    train_code:string, name:string
}

journey = {
    journey_id:number, int:number, train_code:string
}

price = {
    journey_id:number, price:number
}

On the query side, you need to add a FROM and you just change x IN (a, b) to (x = a OR x = b). You'll end up having the following query:

SELECT 
    train.name
FROM   
    train
    JOIN  journey on train.train_code = journey.train_code
    JOIN  price on price.journey_id = journey.journey_id 
WHERE  
    price.price >= 50 
    AND (journey.train_code = 'NYC' OR journey.train_code = 'SFO') 
    AND  journey.int = 1

This format is understood by RelaX, and will give you the result you're looking for:

π train.name σ price.price ≥ 50 and (journey.train_code = 'NYC' or journey.train_code = 'SFO' ) and journey.int = 1 train ⨝ train.train_code = journey.train_code journey ⨝ price.journey_id = journey.journey_id price

enter image description here

That is you have one projection (π), equivalent to your SELECT one selection (σ) that filters with the condition in your WHERE clause, and two joins (⨝) which are equivalent to SQL JOIN.

  • The tool mentions to use DISTINCT (that relational algebra assumes DISTINCT anyway). Does it matter? Also, in relational algebra do you always need to select a field i.e. select * wont work? It seems like you do need to rewrite the query sometimes e.g. I used 'IN' and you used 'OR'. Similarly I need to do a count(x) as total and then have a having total > number line vs a having count(x) > number in the where clause directly in the SQL query... is this expected? – Dino Abraham Jun 21 '17 at 16:49
  • First thing: make sure the SQL works before you try to convert it. Some of the things you mention (count() in your WHERE) don't look like legal SQL. Next: both the tool and relational algebra are *stricter that most implementations that SQL. Relational algebra doesn't have the concept of "IN (a, b, c)", you just talk about "conditions" in abstract. RelaX decided to implement some conditions but maybe not all. – joanolo Jun 21 '17 at 17:44
  • WRT to Distinct: you don't actually need it. The relational algebra expression will be the same whether you have it or not. The message is just telling you that relational algebra is based on sets, where you can't have two times the same element: i.e. every typle is always distinct in all cases. – joanolo Jun 21 '17 at 20:34
  • Great points! In theory, if I am able to convert a SQL code to a relational algebra statement using the tool above, that SQL query will indeed be a "correct" sql statement to run on the same schema as a SQL query? For example give me all train codes with at least two price offers would be Select train.train_code, count(price.journey_id) as count from train join journey on train.journey_id = journey.journey_id join price on price.journey_id = journey.journey_id group by train.train_code having count > 2. Or put the 'having' clause as a where (which works in SQL not in the tool). – Dino Abraham Jun 22 '17 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.