PostgreSQL storage need of references - sql

I'm heavily using references in a SQL layout and was wondering if that's a bad habit. As I declare a reference with varchar(20), does PostgreSQL doubles the storage usage or just uses a hidden ID to link the values?
An example:
create table if not exists distros(
name varchar(20),
primary key(name)
);
create table if not exists releases(
distro varchar(20) references distros(name),
name varchar(20),
primary key(distro, name)
);
create table if not exists targets(
distro varchar(20) references distros(name),
release varchar(20) references releases(name),
name varchar(20),
primary key (distro, release, name)
);
Is the distro value stored once or three times?
Thanks

I am affraid, that your column distro is not stored once or three times, but much more.
It is in each one of your tables. But on top of that you have made it as a part of primary key that in turn make it part of each index you will define for the table.
Create your tables this way. It will save you lot of space and will be faster.
create table if not exists distros(
id serial,
name varchar(20),
primary key(id)
);
create table if not exists releases(
id serial,
distro_id int references distros(id),
name varchar(20),
primary key(id)
);
create table if not exists targets(
id serial,
distro_id int references distros(id),
release_id int references releases(id),
name varchar(20),
primary key (id)
);

your data is repeated. Using the foreign key constraint (a.k.a the "references") simply means that you can not have a value in the column if it doesn't exist in the referenced column.
This tutorial is worth reading.

I do not know Postgres storage layout, but I think, each record should be stored completely in a so called datapage, so that in the case of tablescans (searching without usage of indexes) no additional dereferencing is necessary. that includes also all those referencing attributes.
Additionally it will be stored at least partly in each index, from where the referenced record will be found using some kind of record id, that depends on the indexing technology you are using. The normal B(*)Trees will work in such a way.
So the answer is at least three times and in a kind of cumulating way in each index used to search for the referenced records.

Related

Multiple columns from the same table in another table as foreign keys

I'm trying to make a game called "Odds On". You may have played this before.
Two people decide on a range of numbers and a challenge/dare
They both say their chosen number within the range at the same time.
If the choices are the same, then whoever is 'it' has to complete the challenge/dare
I'm trying to learn and create an Ubuntu server with WinForm clients to make this game online.
With my current plan, I've run into a problem. I would like the game table to hold two user.username(s) as foreign keys as well as two round.roundID(s).
I've tried making the database in access and access said it could not enforce referential integrity
Can this be implemented in mySQL?? Perhaps using linking tables?
UML of what I'm trying to create
I would avoid MS-Access since it has several limitations that could hamper your learning of relational databases.
You can have many relationships between each pair of tables. Your example -- in PostgreSQL -- can look like:
create table users (
username varchar(20) primary key not null,
password varchar(20),
currently_logged_in int
);
create table round (
round_id int primary key not null,
user1_result int,
user2_result int
);
create table game (
game_id int primary key not null,
user1 varchar(20) references users (username),
user2 varchar(20) references users (username),
round1_id int references round (round_id),
round2_id int references round (round_id),
lower_bound int,
upper_bound int
);
See this example at db<>fiddle.

how to create a table with a supervisor referencing another supervisor

I need to create a table explaining how one representative reports to another but dont know quite how?
Create table Representative (RID int , TOID int, Rname varchar(10), Rphone varchar(15), PRIMARY KEY (RID), FOREIGN KEY (TOID) REFERENCES TourOperator);
The code above is my attempt but dont know how to introduce the reports to
do I create another variable called super_ID? and add it to table or how can i relate one representative to another in the table
Yes, you'd add another column (SUPER_ID) into the table which will be a foreign key, pointing to RID.

SQL How to not insert duplicated values

I'm trying to create a procedure that inserts data into a table of registers but i don't want to repeat the second parameter, this is the table
CREATE TABLE Inscription
(
idClass INT references tb_class,
idStudent INT references tb_student,
)
The idea is that a student (idStudent) can register in various classes but not in the same class (idClass), I tried to add a unique constraint in the idStudent column but that only allows a student to register in one single class.
I always suggest that all tables have a numeric primary key. In addition, your foreign key references are not correct. And what you want to do is add a unique constraint.
The exact syntax depends on the database. The following is for SQL Server:
CREATE TABLE Inscriptions (
idInscription int identity(1, 1) primary key
idClass int references tb_classes(idClass),
idStudent int references tb_students(idStudnt)
unique (idClass, idStudent)
);
Notice that I name the tables as the plural of the entity, but the id using the singular.
The Inscriptions table probably wants other columns as well, such as the date/time of the inscription, the method, and other related information.
You are looking to create a constraint on your table that includes both columns idClass and idStudent.
Once that constraint is created, an attempt to insert duplicate class/student will result in an error being raised.
As your table does not seem to include a primary key, you would better make that constraint your primary key.
NB : you did not tell which RDBMS you are using hence cannot give you the exact syntax to use...
Your unique key needs to encompass both idClass and idStudent, so any particular combination cannot repeat itself.

Does oracle provide a built-in currency table for me to use as constraints?

I'm creating a table in Oracle 11g like this:
CREATE TABLE EXAMPLE (
ID VARCHAR2(10) PRIMARY KEY,
NAME VARCHAR2(100),
SHORT VARCHAR2(50),
CURRENCY CHAR(3)
);
Is it possible to create a foreign key constraint or even a check constraint on CURRENCY to a built-in Oracle table that contains the ISO currencies?
Not having a great understanding of databases I also take as input other solutions that might be out there, however I do not want to maintain my own table for this, if it's too much work, I'll live with user errors.
Thanks.
You can get a list of ISO currencies from a built in view in oracle:
select utl_i18n.GET_DEFAULT_ISO_CURRENCY(value) iso_cur
from v$nls_valid_values
where parameter = 'TERRITORY'
But as Nuno Guerreiro said, you'll need to create a table from these results and add a foreign key to the new table.
Note: Edited to include #A.B.Cade's suggestion.
Unfortunately you can't directly add a constraint, as the currencies data is available through a system a view. You can, however, create your own table with that information and then create the foreign key. Here's an example of how you can do it.
CREATE TABLE currencies (
country VARCHAR2(30) PRIMARY KEY,
currency VARCHAR2(3) NOT NULL
);
INSERT INTO currencies
SELECT value country, utl_i18n.get_default_iso_currency(value) currency
FROM v$nls_valid_values
WHERE parameter = 'TERRITORY';
CREATE INDEX currencies_iso_idx ON currencies(currency) COMPUTE STATISTICS;
ALTER TABLE example ADD CONSTRAINT example_currency_fk FOREIGN KEY (currency)
REFERENCES currencies(currency);
The example above includes an index on the currency value, as I suspect that will what you'll be querying on.
Actually I don't understand what do you mean by "default Oracle table that contains ISO currencies" (do you mean Oracle PeopleSoft CURRENCY_CD_TBL table?), but in general you can alter your table after creation to add foreign key constraint.
Here is an example:
ALTER TABLE EXAMPLE
ADD CONSTRAINT fk_currency
FOREIGN KEY (CURRENCY)
REFERENCES put_parent_table_name_here(_corresponding_field_name_in_perent_table);
You also can add constraint definition into CREATE TABLE statement.
Here is an example:
CREATE TABLE EXAMPLE (
ID VARCHAR2(10) PRIMARY KEY,
NAME VARCHAR2(100),
SHORT VARCHAR2(50),
CURRENCY CHAR(3),
CONSTRAINT fk_currency
FOREIGN KEY (CURRENCY)
REFERENCES put_parent_table_name_here(_corresponding_field_name_in_perent_table)
);

Correct way to create a table that references variables from another table

I have these relationships:
User(uid:integer,uname:varchar), key is uid
Recipe(rid:integer,content:text), key is rid
Rating(rid:integer, uid:integer, rating:integer) , key is (uid,rid).
I built the table in the following way:
CREATE TABLE User(
uid INTEGER PRIMARY KEY ,
uname VARCHAR NOT NULL
);
CREATE TABLE Recipes(
rid INTEGER PRIMARY KEY,
content VARCHAR NOT NULL
);
Now for the Rating table: I want it to be impossible to insert a uid\rid that does not exist in User\Recipe.
My question is: which of the following is the correct way to do it? Or please suggest the correct way if none of them are correct. Moreover, I would really appreciate if someone could explain to me what is the difference between the two.
First:
CREATE TABLE Rating(
rid INTEGER,
uid INTEGER,
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid),
FOREIGN KEY (rid) REFERENCES Recipes,
FOREIGN KEY (uid) REFERENCES User
);
Second:
CREATE TABLE Rating(
rid INTEGER REFERENCES Recipes,
uid INTEGER REFERENCES User,
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid)
);
EDIT:
I think User is problematic as a name for a table so ignore the name.
Technically both versions are the same in Postgres. The docs for CREATE TABLE say so quite clearly:
There are two ways to define constraints: table constraints and column constraints. A column constraint is defined as part of a column definition. A table constraint definition is not tied to a particular column, and it can encompass more than one column. Every column constraint can also be written as a table constraint; a column constraint is only a notational convenience for use when the constraint only affects one column.
So when you have to reference a compound key a table constraint is the only way to go.
But for every other case I prefer the shortest and most concise form where I don't need to give names to stuff I'm not really interested in. So my version would be like this:
CREATE TABLE usr(
uid SERIAL PRIMARY KEY ,
uname TEXT NOT NULL
);
CREATE TABLE recipes(
rid SERIAL PRIMARY KEY,
content TEXT NOT NULL
);
CREATE TABLE rating(
rid INTEGER REFERENCES recipes,
uid INTEGER REFERENCES usr,
rating INTEGER NOT NULL CHECK (rating between 0 and 5),
PRIMARY KEY(rid,uid)
);
This is a SQL Server based solution, but the concept applies to most any RDBMS.
Like so:
CREATE TABLE Rating (
rid int NOT NULL,
uid int NOT NULL,
CONSTRAINT PK_Rating PRIMARY KEY (rid, uid)
);
ALTER TABLE Rating ADD CONSTRAINT FK_Rating_Recipies FOREIGN KEY(rid)
REFERENCES Recipies (rid);
ALTER TABLE Rating ADD CONSTRAINT FK_Rating_User FOREIGN KEY(uid)
REFERENCES User (uid);
This ensures that the values inside of Rating are only valid values inside of both the Users table and the Recipes table. Please note, in the Rating table I didn't include the other fields you had, just add those.
Assume in the users table you have 3 users: Joe, Bob and Bill respective ID's 1,2,3. And in the recipes table you had cookies, chicken pot pie, and pumpkin pie respective ID's are 1,2,3. Then inserting into Rating table will only allow for these values, the minute you enter 4 for a RID or a UID SQL throws an error and does not commit the transaction.
Try it yourself, its a good learning experience.
In Postgresql a correct way to implement these tables are:
CREATE SEQUENCE uid_seq;
CREATE SEQUENCE rid_seq;
CREATE TABLE User(
uid INTEGER PRIMARY KEY DEFAULT nextval('uid_seq'),
uname VARCHAR NOT NULL
);
CREATE TABLE Recipes(
rid INTEGER PRIMARY KEY DEFAULT nextval('rid_seq'),
content VARCHAR NOT NULL
);
CREATE TABLE Rating(
rid INTEGER NOT NULL REFERENCES Recipes(rid),
uid INTEGER NOT NULL REFERENCES User(uid),
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid)
);
There is no real difference between the two options that you have written.
A simple (i.e. single-column) foreign key may be declared in-line with the column declaration or not. It's merely a question of style. A third way should be to omit foreign key declarations from the CREATE TABLE entirely and later add them using ALTER TABLE statements; done in a transaction (presumable along with all the other tables, constraints, etc) the table would never exist without its required constraints. Choose whichever you think is easiest fora human coder to read and understand i.e. is easiest to maintain.
EDIT: I overlooked the REFERENCES clause in the second version when I wrote my original answer. The two versions are identical in terms of referential integrity, there are just two ways of syntax to do this.