# Converting SQL to Relational Algebra / Calculus

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.

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 `JOIN`ing.
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

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? Commented Jun 21, 2017 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. Commented Jun 21, 2017 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. Commented Jun 21, 2017 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). Commented Jun 22, 2017 at 15:22