Relation "table" already exists - sql

I'm building a SQL database and running into the error "relation 'sexes' already exists".
Per SO users that posted about a similar problem, I've attempted: commenting out constraints to see if those were interfering, changing all references to serial/ all primary keys to integers to match up types, dropping all tables if they exist. The error remains the same no matter what I do so I've posted my original code. I could really use some guidance as to what the issue in this case is. Thanks!
CREATE TABLE sexes (
id serial PRIMARY KEY,
string text NOT NULL
);
CREATE TABLE humans (
id serial PRIMARY KEY UNIQUE NOT NULL,
forename text NOT NULL,
surname text NOT NULL,
birthdate date,
sex_id integer REFERENCES sexes(id)
);
CREATE TABLE marriages (
id serial PRIMARY KEY UNIQUE NOT NULL,
partner_1_id integer REFERENCES humans(id),
partner_2_id integer REFERENCES humans(id),
marriage_date date NOT NULL,
divorce_date date NOT NULL,
CONSTRAINT divorced CHECK (marriage_date <= divorce_date),
CONSTRAINT marry_self CHECK (partner_1_id <> partner_2_id)
);

You could use IF NOT EXISTS clause:
Do not throw an error if a relation with the same name already exists. A notice is issued in this case. Note that there is no guarantee that the existing relation is anything like the one that would have been created.
CREATE TABLE IF NOT EXISTS sexes (
id serial PRIMARY KEY,
string text NOT NULL
);
Which is really strange because dropping the tables if they existed before creating new ones threw back a whole new error.
If you want to drop tables you have to do it in right order:
DROP TABLE IF EXISTS marriages;
DROP TABLE IF EXISTS humans;
DROP TABLE IF EXISTS sexes;

Related

SQL : how to check value used in other table?

CREATE TABLE sectors
(
name varchar,
id integer,
capacity integer
)
CREATE TABLE employees
(
id integer,
for_sector_id integer,
name varchar
)
Here I need to check if entered for_sector_id is whether null or already using in data of sectors. Thought about adding check clause down by create script:
CREATE TABLE employees
(
...
CHECK(for_sector_id is null or for_sector_id in sectors.id)
)
May this solve the problem?
If you just need to check that the reference is valid then you can use a foreign key reference:
CREATE TABLE sectors (
id integer primary key,
name varchar,
capacity integer
);
CREATE TABLE employees (
id integer,
for_sector_id integer,
name varchar(255), -- you want a length in most databases
foreign key for_sector_id references sector(id)
);
The referenced id needs to be a primary or unique key.
EDIT:
I originally misunderstood the question. I thought the sector needed to be "marked as used" in the sector table to be valid (say by having capacity > 0). The OP appears to merely want its existence in the table.
For this situation, I can think of three options if you want a "conditional" foreign key reference (i.e. there is a used flag or say, capacity > 0):
A trigger
A user-defined function for the check constraint
A funky foreign key relationship that uses a computed column
Not all databases support all of these. (As I write this, you haven't specified the database, so I'm only answering the question that you have explicitly asked and not elaborating.)

Can I use a foreign key to the implicit rowid?

I want to create a database that supports "friendships".
I've come up with (but don't know exactly if it works):
users:
"create table if not exists user (
name text not null,
password text not null
)"
friendships:
"create table if not exists friendship (
user1 int not null,
user2 int not null,
foreign key(user1) references user(rowid),
foreign key(user2) references user(rowid)
)"
Will this work?
The documentation says:
The parent key is the column or set of columns in the parent table that the foreign key constraint refers to. This is normally, but not always, the primary key of the parent table. The parent key must be a named column or columns in the parent table, not the rowid.
Please note that hidden rowid values are not guaranteed to keep their values (e.g., after a VACUUM), so in any case, it would be a good idea to make the parent key an explicitly named column.

Enforcing existence of many-to-many and one-to-one information at the same time (PostgreSQL)

The relation "astronomers discover stars" is m:n, as an astronomer can discover many stars, and a star can as well be discovered from many astronomers.
In any case however, there will be a single date of discovery for every star. If there are many astronomers working on it, they should do it simultaneously, otherwise, only the first one gets the credits of the discovery.
So, in PostgreSQL, we have:
CREATE TABLE astronomer (
astronomer_id serial PRIMARY KEY,
astronomer_name text NOT NULL UNIQUE
);
CREATE TABLE star (
star_id serial PRIMARY KEY,
star_name text NOT NULL UNIQUE,
discovery_date date
);
CREATE TABLE discovered (
star_id integer NOT NULL REFERENCES star,
astronomer_id integer NOT NULL REFERENCES astronomer,
CONSTRAINT pk_discovered PRIMARY KEY (star_id, astronomer_id)
);
Now the trick question: I want to enforce that whenever there is a discovery date for a star, there will be at least one entry in the discovered table, and vice versa.
I could create a unique key (star_id, discovery_date) in table star, and then use that combination as a foreign key in table discovered instead of the star_id. That would solve half of the problem, but still leave it possible to have a discovered_date without astronomers for it.
I can't see any simple solution other than using a trigger to check, or only allowing data enter via a stored procedure that will at the same time insert a discovery_date and entries into the table discovered.
Any ideas?
Thank you!
I would just move the discovery_date column to the discovered table
CREATE TABLE astronomer (
astronomer_id serial PRIMARY KEY,
astronomer_name text NOT NULL UNIQUE
);
CREATE TABLE star (
star_id serial PRIMARY KEY,
star_name text NOT NULL UNIQUE
);
CREATE TABLE discovered (
star_id integer NOT NULL REFERENCES star,
astronomer_id integer NOT NULL REFERENCES astronomer,
discovery_date date not null,
CONSTRAINT pk_discovered PRIMARY KEY (star_id, astronomer_id)
);
Now you have the problem of multiple dates for the same star but as you say in the question only the first one(s) will get the credit.

PostgreSQL 9.1 primary key autoincrement

I'm trying to add a primary key with an autoincrement.
I have read some docs and other questions - there're SERIAL and nextval() statements but neither of them work.
Here's what I made:
CREATE TABLE IF NOT EXISTS "category" (
"id" integer SERIAL PRIMARY KEY,
"name" varchar(30) DEFAULT NULL
); // the error near "SERIAL"
and
CREATE SEQUENCE your_seq;
CREATE TABLE IF NOT EXISTS "category" (
"id" integer PRIMARY KEY nextval('your_seq'),
"name" varchar(30) DEFAULT NULL
); // the error near 'nextval'
What am I doing wrong? Is there a way to increment the primary key by 1.
serial is, more or less, a column type so saying integer serial is like saying text text, just say serial:
CREATE TABLE IF NOT EXISTS "category" (
"id" SERIAL PRIMARY KEY,
"name" varchar(30) DEFAULT NULL
);
If you want to create the sequence yourself then you want to make the default value of id the next value in the sequence and that means saying default nextval('your_seq'):
CREATE SEQUENCE your_seq;
CREATE TABLE IF NOT EXISTS "category" (
"id" integer PRIMARY KEY default nextval('your_seq'),
"name" varchar(30) DEFAULT NULL
);
To simulate the usual serial behavior you'll also want to make the sequence owned by the table:
alter sequence your_seq owned by category.id;
Reading the Serial Types section of the manual might be fruitful.
I'd also recommend that you don't double quote your table and column names unless you have to. PostgreSQL will fold your identifiers to lower case so id and "id" will be the same thing but unnecessary quoting is a bad habit that can easily lead to a big mess of quotes everywhere.
If someone needs to modify an existing table to add a primary key with auto-increment:
ALTER TABLE table_name ADD COLUMN pk_column_name SERIAL PRIMARY KEY;

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.