Postgresql multiple tables with same foreign key unique constraint - sql

I have following tables on PostgreSQL 9.4
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL
);
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
Is it possible to force user_id value to be unique across tables dealer and affiliate?

There are different setups to use for inheritance in SQL and for this you could just use an integer column type in the table user that marks the type of the user and would reference to table user_type (id,name) that would have the values 1,dealer and 2,affiliate:
CREATE TABLE user_type (
id INTEGER PRIMARY KEY, --could be SERIAL
name text
);
INSERT INTO user_type VALUES (1,'dealer'), (2, 'affiliate');
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL,
user_type INTEGER REFERENCES user_type NOT NULL,
UNIQUE(id,user_type)
);
This in itself wouldn't force uniqueness across tables so after implementing this you would have the following options:
Drop the tables dealer and affiliate - you won't need them if you rely on the type field to see which one the user is.
If you have to keep those inherited tables you can:
Use triggers - these triggers check the uniqueness and would be actived on INSERT or UPDATE
Another (a bit clumsy) solution: add user_type field to both subtables like this:
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 1 check (user_type = 1),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 2 check (user_type = 2),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
The checks and foreign keys together make sure you cannot have both types of user in the main table. Note that user_id might be used as the PRIMARY KEY in the subtables too. Currently a row in user might have several dealer rows linked to it so at least you might want to set user_id foreign keys in subtables as UNIQUE.

Related

Design sql tables with list of foreign keys

I want to create an application for rotating pairs in a team every day. I need to store this in the database. Requirments are:
A team should be assigned to one ore more members.
Each team can have multiple tabs and different members allocate in them.(If team consist of 4 members for the particular tab only 3 should be part of it)
Each tab will have a pair of members or list of pairs per day stored.
I have ended up designing something like the example below:
create table if not exists team (
id serial not null primary key,
name text not null
);
create table if not exists member (
id serial not null primary key,
team_id integer references team(id),
nickname text
);
create table if not exists team_tab (
id bigserial not null primary key,
team_id integer references team(id) on delete cascade,
name text not null,
member_ids integer[],
);
create table if not exists team_tab_pairs (
id bigserial not null primary key,
team_tab_id integer not null references team_tab(id) on delete cascade,
tab_date date not null,
pair_ids integer[][],
);
I need an advice and suggestions how could I achieve this without having a list of references ids stored in the 2 tables below.
You need an extra table to design an M:N relationship. This is the case, for example, between "team tab" and "member". In addition to both main entities:
create table member (
id serial not null primary key,
team_id integer references team(id),
nickname text
);
create table team_tab (
id bigserial not null primary key,
team_id integer references team(id) on delete cascade,
name text not null
);
...you'll need to create a table to represent the M:N relationship, as in:
create table team_tab_member (
team_tab_id bigint not null,
member_id int not null,
primary key (team_tab_id, member_id) -- optional depending on the model
);

How can I fix this PostgreSQL foreign key error?

I have created three tables (users, candidates and votes), and when a user create a vote, it is sent to the votes table which has a foreign key candidate from the candidates table, but when I create a new vote, I get this error
ERROR: insert or update on table "votes" violates foreign key constraint "votes_candidate_fkey"
DETAIL: Key (candidate)=(6) is not present in table "candidates".
The candidate table has the candidate with id 6, but when I create a vote I get a foreign key error, how can I solve this, below is the shema
CREATE TABLE IF NOT EXISTS users(
id serial PRIMARY KEY,
first_name VARCHAR (100) NOT NULL,
last_name VARCHAR (100) NOT NULL,
other_name VARCHAR (100) NOT NULL,
email VARCHAR (100) UNIQUE NOT NULL,
password VARCHAR (100) NOT NULL,
phone_Number VARCHAR (100) UNIQUE NOT NULL,
passport_Url VARCHAR (255) NOT NULL,
is_Admin BOOLEAN DEFAULT 'no'
);
CREATE TABLE IF NOT EXISTS candidates(
id serial PRIMARY KEY,
office INTEGER REFERENCES offices(id),
party INTEGER REFERENCES parties(id),
candidate INTEGER UNIQUE REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS votes(
created_by INTEGER REFERENCES users(id),
office INTEGER REFERENCES offices(id),
candidate INTEGER REFERENCES candidates(id),
created_On DATE NOT NULL DEFAULT NOW(),
PRIMARY KEY (office, created_By)
);
User 6 exists, but you only have five candidates and their ids are 1, 2, 3, 4, and 5.
Your foreign key is to id, not the candidate column:
candidate INTEGER REFERENCES candidates(id),
----------------------------------------^
The appropriate id is 5, for user 6.
You may want to set up the candidates table with the primary key being the user id (that is, candidates are subsets of users). If so remove the serial column:
CREATE TABLE IF NOT EXISTS candidates(
candidate INTEGER PRIMARY KEY REFERENCES users(id),
office INTEGER REFERENCES offices(id),
party INTEGER REFERENCES parties(id)
);
I would recommend this. If you as the database designer are already confused about the difference between a "candidate" and a "user", then no doubt future users of the database will have the same confusion.
The message is very much clear that your candidates tabled does not contain id=6 but you are trying to insert that value into votes tables that's why you got the error, cause it is a foreign key violation
in votes table candidate INTEGER REFERENCES candidates(id) this is relate to candidates tables id column not with candidate column that you thought

join table referencing non unique foreign key

I have the following tables in a database. phrases allows duplicate phrases to be stored.
CREATE TABLE phrases (
id INTEGER PRIMARY KEY,
phrase VARCHAR(1000),
creation_date TIMESTAMP WITH TIME ZONE NOT NULL,
);
CREATE TABLE intents (
id INTEGER PRIMARY KEY,
name VARCHAR(10) UNIQUE
);
I would like to create a join table between phrases and intents. I want to enforce that:
each phrase exists in the phrases table
each phrase only appears once
The following fails because the foreign key in phrases is not unique.
CREATE TABLE phrases_intents (
phrase VARCHAR(1000) REFERENCES phrases (phrase),
intent VARCHAR(10) REFERENCES intents (name),
PRIMARY KEY (phrase),
);
What is best practice to allow this functionality?
Modify the phrases table to have a unique key for foreign key relationships. Perhaps:
CREATE TABLE phrases (
id INTEGER PRIMARY KEY,
phrase VARCHAR(1000),
creation_date TIMESTAMP WITH TIME ZONE NOT NULL,
unique (phrase, id)
);
Then use this key in phrase_intents:
CREATE TABLE phrase_intents (
phrase_intents_id serial primary key,
phrase varchar(1000) not null,
phrase_id int not null,
intent_id int references intents (id),
foreign key (phrase, phrase_id) references phrases(phrase, id),
unique (phrase)
);
Your conditions are satisfied:
Each phrase is in the phrases table because of not null and the foreign key reference.
Each distinct phrase appears in this table at most once. This is because of the unique constraint on phrase.
For each phrase to appear exactly once requires populating the table. You will then need triggers on your table to be sure that when a new phrase is created, then a row is inserted.

How do I make a serial field auto increment and be a foreign key - Postgres

I have 2 tables and I am trying to create a Foreign Key between the two. Here is the structure of my tables:
create table users (
id serial,
user_name varchar(50)
);
create table playlists (
id serial,
user_id integer references users(id)
);
I keep getting this error:
ERROR: there is no unique constraint matching given keys for referenced table "users"
Why is there not a unique constraint? If I create the id in the users table as integer PRIMARY KEY, then everything works fine. How do I fix this where the users id auto increments and can be the FK in the playlists table?
Creating a column of type serial doesn't make it the primary key or constraint it in any way. serial just creates an integer column, creates a sequence, and attaches the sequence to the column to provide default values. From the fine manual:
In the current implementation, specifying:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
If you want your id serial columns to be primary keys (which you almost certainly do), then say so:
create table users (
id serial not null primary key,
user_name varchar(50)
);
create table playlists (
id serial not null primary key,
user_id integer references users(id)
);

Is it possible to reference a different column in the same table?

If a blog has a 'categories' table such as the following:
CREATE TABLE categories
(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
parent_id INTEGER NOT NULL,
name VARCHAR(30) NOT NULL,
description TEXT,
count INTEGER NOT NULL DEFAULT 0
);
And if the parent_id field is intended to refer to the 'id' field of the categories table, then how could I add a constraint that would ensure that values inserted into parent_id references the id field?
I simply want to make sure that only category id values that exist can be used as a parent of a newly inserted category.
Yes, you can reference a column in the same table.
But that column should be nullable otherwise you can't insert the first record.
CREATE TABLE categories
(
id INTEGER PRIMARY KEY AUTO_INCREMENT,
parent_id INTEGER NULL,
name VARCHAR(30) NOT NULL,
description TEXT,
count INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY (parent_id) REFERENCES categories(id)
);
Note that after the REFERENCES keyword the table name is not optional, so you must specify it even if you are referencing a column in the same table. From the documentation:
reference_definition:
REFERENCES tbl_name (index_col_name,...)
[MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
[ON DELETE reference_option]
[ON UPDATE reference_option]
See it working online: sqlfiddle
Just use a normal foreign key:
ALTER TABLE categories ADD CONSTRAINT FK_categories_Parent_ID
REFERENCES categories (ID)
However Parent_ID should be nullable as you'll never be able to insert a record
You can use below link. It has how you can do it Oracle database.
http://www.adp-gmbh.ch/ora/data_samples/hierarchic_yahoo.html
Thanks