SQL Database Design (Manager and Workers relationship) - sql

CREATE TYPE VALID_ACCOUNT_TYPE AS ENUM ('Admin', 'Manager', 'Worker');
CREATE TYPE VALID_LANGUAGE AS ENUM ('en', 'th');
CREATE TABLE IF NOT EXISTS users (
user_id SMALLSERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE CONSTRAINT username_constraint CHECK (username ~ '^[A-Z0-9_-]{1,15}$'),
disabled BOOLEAN NOT NULL DEFAULT FALSE,
password TEXT NOT NULL,
plain_password TEXT NOT NULL,
created TIMESTAMP WITHOUT TIME ZONE NOT NULL,
modified TIMESTAMP WITHOUT TIME ZONE NOT NULL
);
CREATE TABLE IF NOT EXISTS user_details (
user_id SMALLINT PRIMARY KEY REFERENCES users,
account_type VALID_ACCOUNT_TYPE NOT NULL,
language VALID_LANGUAGE NOT NULL DEFAULT 'en',
nickname TEXT NOT NULL CONSTRAINT nickname_constraint CHECK (nickname ~ '^.{1,15}$') DEFAULT 'No Nickname',
phone_number TEXT NOT NULL CONSTRAINT phone_number_constraint CHECK (phone_number ~ '^[0-9]{10}$') DEFAULT 'No Phone Number',
line_username TEXT NOT NULL CONSTRAINT nickname_constraint CHECK (nickname ~ '^.{1,15}$') DEFAULT 'No Line Username',
created TIMESTAMP WITHOUT TIME ZONE NOT NULL,
modified TIMESTAMP WITHOUT TIME ZONE NOT NULL
);
I have following table and after creating these I want to have another table that describes relationship between Manager(One) to Workers(Many). One manager can have many workers. And one worker can only have one manager. How should I approach the table creation?
I currently have
CREATE TABLE IF NOT EXISTS user_relationships (
user_id1 SMALLINT REFERENCES users NOT NULL,
user_id2 SMALLINT REFERENCES users NOT NULL,
created TIMESTAMP WITHOUT TIME ZONE NOT NULL,
modified TIMESTAMP WITHOUT TIME ZONE NOT NULL,
UNIQUE (user_id1, user_id2)
);
but this doest not have any constraint about Manager/Worker at all.

Related

SQL query that calculates, on a daily basis, the absolute number of active users, and the percentage of active users among all users

I have to build a SQL query, ideally SQLlite syntax, that calculates
on a daily basis, the absolute number of active users, and the percentage of active users among all users. An active user is defined as a user to be active one some day X, if the user listened to at least one song in the time interval [X-6 days,X] . The result should adhere to the following schema꞉
1 row per day
3 columns꞉ (date, number_active_users, percentage_active_users)
We have the following Schema:
-- Tables
-- tracks dimension
CREATE TABLE IF NOT EXISTS tracks(
recording_msid TEXT NOT NULL,
track_name TEXT NOT NULL,
release_msid TEXT NOT NULL,
release_name TEXT NOT NULL,
release_mbid TEXT DEFAULT NULL,
recording_mbid TEXT DEFAULT NULL,
isrc TEXT DEFAULT NULL,
track_number TEXT DEFAULT NULL,
track_mbid TEXT DEFAULT NULL,
work_mbids TEXT DEFAULT NULL,
dedup_tag TEXT DEFAULT NULL,
tags TEXT DEFAULT NULL,
release_group_mbid TEXT DEFAULT NULL,
artist_names TEXT DEFAULT NULL,
discnumber INT DEFAULT NULL,
release_artist_name TEXT DEFAULT NULL,
release_artist_names TEXT DEFAULT NULL,
rating INT DEFAULT NULL,
source TEXT DEFAULT NULL,
track_length INT DEFAULT NULL,
albumartist TEXT DEFAULT NULL,
totaldiscs INT DEFAULT NULL,
totaltracks INT DEFAULT NULL,
choosen_by_user TEXT DEFAULT NULL,
PRIMARY KEY (recording_msid,track_name)
);
-- users dimension
CREATE TABLE IF NOT EXISTS users(
user_name TEXT PRIMARY KEY,
spotify_id TEXT DEFAULT NULL,
spotify_album_artist_ids TEXT DEFAULT NULL,
spotify_album_id INTEGER DEFAULT NULL,
spotify_artist_ids TEXT DEFAULT NULL
);
-- artists dimension
CREATE TABLE IF NOT EXISTS artists(
artist_msid TEXT PRIMARY KEY,
artist_name TEXT NOT NULL,
artist_mbids TEXT DEFAULT NULL
);
-- fact table user history
CREATE TABLE IF NOT EXISTS user_history(
listened_at NUMERIC NOT NULL,
track_name TEXT NOT NULL,
recording_msid TEXT NOT NULL,
user_name TEXT NOT NULL,
artist_msid TEXT NOT NULL,
duration_ms INT DEFAULT NULL,
duration INT DEFAULT NULL,
listening_from NUMERIC DEFAULT NULL,
"date" NUMERIC DEFAULT NULL,
FOREIGN KEY(track_name) REFERENCES tracks(track_name),
FOREIGN KEY(recording_msid) REFERENCES tracks(recording_msid),
FOREIGN KEY(user_name) REFERENCES users(user_name),
FOREIGN KEY(artist_msid) REFERENCES artists(artist_msid)
);
Any help or simple pointing in the right direction will do. Thanks! Some alterations to the schema are also possible
This is what I tried but it gives only one date group
with user_groups as(
select date(listened_at, 'unixepoch','localtime') as dt, count(user_name) as cnt
ROW_NUMBER() OVER (ORDER BY date(listened_at, 'unixepoch','localtime'))
as row_no
FROM user_history GROUP by date(listened_at, 'unixepoch','localtime')
)
select dt as date, cnt as active_users, cnt/SUM(cnt) as percentage
from user_groups
where row_no between 1 and 6;
try self joins. I cannot write an SQL but know that this can be easily solved by creating a 6 way self join. Self join works the same way in SQLlite as in other databases

PostgreSQL: How to link 2 tables?

I have a table defined like this:
CREATE TABLE public.journeys (
journey_id uuid NOT NULL UNIQUE DEFAULT uuid_generate_v4(),
name text NOT NULL,
user_id uuid NOT NULL,
date_created timestamptz NOT NULL,
date_deleted timestamptz NULL,
route_id uuid NOT NULL,
CONSTRAINT fk_users
FOREIGN KEY(user_id)
REFERENCES users(user_id)
);
What I want to do now is create a second table that will connect to this table above. Here's its definition:
CREATE TABLE public.routes (
route_id uuid NOT NULL UNIQUE DEFAULT uuid_generate_v4(),
idx smallint NOT NULL,
date timestamptz NULL,
latitude real NOT NULL,
longitude real NOT NULL,
CONSTRAINT route_key
PRIMARY KEY (route_id, idx),
CONSTRAINT fk_journeys
FOREIGN KEY(route_id)
REFERENCES journeys(route_id)
);
The notion is that for every Journey there will be a connected Route that simply consists of a series of Latitude, Longitude points. So for a given route_id in journeys there will be N records in routes. Every record in a given route will share the same route_id but each one will have a unique idx (ie. 0, 1, 2, ...).
This is the error I'm getting when I try creating public.routes:
SQL Error [42830]: ERROR: there is no unique constraint matching given keys for referenced table "journeys"
What am I doing wrong and how do I fix this?
Robert
I read several more threads on the subject and then realized that that journeys.route_id was not being declared as UNIQUE.
So within the public.journeys declaration, this fixed the problem:
route_id uuid NOT NULL UNIQUE,

using foreign key value directly in INSERT INTO statement

is it possible to use the value of the foreign key directly with an INSERT INTO statement? I am using Postgresql and the tables are consttructed as follows:
CREATE TABLE public.sensors
(
name character varying(100) COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
id integer NOT NULL DEFAULT nextval('sensors_id_seq'::regclass),
CONSTRAINT sensors_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.sensors
OWNER to postgres;
Now I also have another table, defined as:
CREATE TABLE public.testmap
(
sensor_id integer NOT NULL,
"timestamp" timestamp with time zone NOT NULL,
value "char" NOT NULL,
CONSTRAINT ragmap_sensor_id_fkey FOREIGN KEY (sensor_id)
REFERENCES public.sensors (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.ragmap
OWNER to postgres;
Now, I try to insert a record directly into the testmap table as:
INSERT INTO testmap (sensor_id, timestamp, value) VALUES (1, NOW(), 'r')
I have a record inserted into the sensors table where the id is 1. However, when I try the INSERT INTO operation, I get:
DETAIL: Key (sensor_id)=(1) is not present in table "sensors".
Is there a way to use the INSERT INTO with the foreignh key directly without having to resort to another Select for the relevant row selection in the sensors table?
Your code doesn't even work. The column id is specified more than once for sensors.
I don't recommend having a character column as a primary key. If you do so, you should be explicit about your types:
INSERT INTO testmap (sensor_id, timestamp, value)
VALUES ('1', NOW(), 'r');
The problem is that your foreign key reference is a number but the primary key is an integer.
Instead, define the primary key to be a number:
CREATE TABLE public.sensors (
id serial primary key,
name character varying(100) COLLATE pg_catalog."default",
description text COLLATE pg_catalog."default",
id integer NOT NULL DEFAULT nextval('sensors_id_seq'::regclass),
CONSTRAINT sensors_pkey PRIMARY KEY (id)
)

Inheritance PostgreSQL

I have 2 tables under PostgreSQL:
a table property that is the mother table (id, created_at ..) and
a habitation table (surface, room, etc...) that inherits property. On the mother table, I have a many-many relationship table. I have added results in the "habitation" table.
When I try to insert "property_table" with habitation IDs, I have a SQL error telling me that the property_id ID does not exist. It exists when I go to see the property or habitation table. I want to insert habitation IDs (so property) in property_tag , should I force insert? Help please
The SQL schemas :
CREATE TABLE "property"
(
id serial NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
address_id int NOT NULL,
permission int NOT NULL DEFAULT 6,
user_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (address_id) REFERENCES "address"(id),
FOREIGN KEY (user_id) REFERENCES "user"(id)
);
CREATE TABLE habitation (
total_surface float,
living_surface float,
ground_surface float,
ground_surface_unity character varying(15) DEFAULT 'm2',
room integer,
bedroom integer,
floor integer,
level integer,
year integer
) INHERITS (property);
CREATE TABLE property_tag
(
tag_id int NOT NULL,
property_id int NOT NULL,
PRIMARY KEY (tag_id, property_id),
FOREIGN KEY (tag_id) REFERENCES "tag"(id) ON DELETE CASCADE,
FOREIGN KEY (property_id) REFERENCES "property"(id) ON DELETE CASCADE
);
CREATE TABLE "tag"
(
id serial NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
name character varying(127) NOT NULL,
user_id int NOT NULL,
color character varying(7) NOT NULL DEFAULT 'A4A4A8',
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE
);
When you insert into table "habitation", the row exists physically only in table "habitation", but not in "property".
Your table "property_tag" references to table "property" (which have no rows, cause rows are in table "habitation") and therefore you are getting error during insert.
You have to change your reference in table "property_tag" from "property" to "habitation".

ERROR: there is no unique constraint matching given keys for referenced table "users"

I have read through some of the similar questions and answers and I don't quit understand the problem. One of my current guess is that Potgres might not allow foreign key-ing of non-primary key.
user:
user registration, 1 user per row, 1 id per row(serial), unique email(primary key)
user_logins:
information about user logins, references user_id from user as foreign key, the rest of the columns together makes a composite primary key
CREATE TABLE users
(
unique_email TEXT NOT NULL,
password TEXT NOT NULL,
user_id SERIAL,
created_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT LOCALTIMESTAMP,
CONSTRAINT emailPK
PRIMARY KEY(unique_email)
);
CREATE TABLE user_logins
(
user_id SERIAL,
login_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT LOCALTIMESTAMP,
login_ip INET,
CONSTRAINT user_idFK
FOREIGN KEY (user_id)
REFERENCES users(user_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT composit_PK_logins
PRIMARY KEY(user_id, login_date, login_ip)
);
user_id must have unique constraints in users table. Otherwise, it will have ambiguities.
In this query, I added UNIQUE constraint in user_id
CREATE TABLE users
(
unique_email TEXT NOT NULL,
password TEXT NOT NULL,
user_id SERIAL UNIQUE,
created_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT LOCALTIMESTAMP,
CONSTRAINT emailPK
PRIMARY KEY(unique_email)
);