Query two tables with one to many relationship - postgresql

I'm using two Postgres tables that have a one to many relationship. The primary table is called users and the other table is called files.
The users table has the following columns:
id SERIAL PRIMARY KEY,
email VARCHAR(128) NOT NULL,
username VARCHAR(128) UNIQUE NOT NULL,
password_hash VARCHAR(128) NOT NULL
The files table has the following columns:
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
title VARCHAR(128) NOT NULL,
url VARCHAR(128) NOT NULL
When I log into my app, I'm querying all the files to display by doing
cur.execute('SELECT * from files')
and when I want a specific users files I run
cur.execute('SELECT * from files where user_id = %i' % user_id)
For my query that fetches all the files, I'd like to adjust it so that I get the username associated with each file also. How should I tailor my execute statement to make that happen?

Try the following. I know this syntax would work with other dbms':
cur.execute('SELECT f.*, u.username from files as f, users as u where u.id = f.user_Id)

Related

Not able to create a foreign key; Relation " " does not exist

I am trying to create a foreign key called 'user_id' for a 'transactions' table where the user_id references the 'user_accounts' table 'id' column. I keep getting an error when I execute the script that says:
SQL Error [42P01]: ERROR: relation "user_accounts" does not exist
The table clearly exists as I have been populating the user_accounts table with data that can be viewed in dbeaver. I am using Postgres and I am aware that quotes/capitalization can really make things difficult but I have executed my entire script without capitalizing or using quotes on any of the table or column names. Although, I did capitalize some of my column data types and I am wondering if that is the issue here? If so, what direction should I take to get my foreign key to work?
My script:
create table if not exists user_accounts (
id serial primary key,
first_name VARCHAR(30),
last_name VARCHAR(30),
username VARCHAR(20),
password VARCHAR(20),
deposit INT,
creditScore INT
)
create table if not exists transactions (
transaction_id serial primary key,
user_id INT references user_accounts(id) not null,
transaction_type VARCHAR(20),
amount INT
)

IBM Db2 on Cloud script creating tables in the wrong schema

On IBM Db2 on Cloud I have imported a script. I created a new schema under which I want to have the new tables created, but when I run the script, it keeps trying to create the tables in a previous schema. Not sure how to get the scripts to create the tables in the new schema.
I have tried the below script without the .SQL_GROUPING_SORTING and it tries to add the tables to a different schema. I have changed the default schema in the Run SQL window within db2 to SQL_GROUPING_SORTING and am now getting the error
""KZF72118" does not have the privilege to perform operation "IMPLICIT CREATE SCHEMA".. SQLCODE=-552, SQLSTATE=42502, DRIVER=4.26.14"
DDL statement for table 'HR' database:
CREATE TABLE EMPLOYEES.SQL_GROUPING_SORTING (
EMP_ID CHAR(9) NOT NULL,
F_NAME VARCHAR(15) NOT NULL,
L_NAME VARCHAR(15) NOT NULL,
SSN CHAR(9),
B_DATE DATE,
SEX CHAR,
ADDRESS VARCHAR(30),
JOB_ID CHAR(9),
SALARY DECIMAL(10,2),
MANAGER_ID CHAR(9),
DEP_ID CHAR(9) NOT NULL,
PRIMARY KEY (EMP_ID));
CREATE TABLE JOB_HISTORY.SQL_GROUPING_SORTING (
EMPL_ID CHAR(9) NOT NULL,
START_DATE DATE,
JOBS_ID CHAR(9) NOT NULL,
DEPT_ID CHAR(9),
PRIMARY KEY (EMPL_ID,JOBS_ID));
CREATE TABLE JOBS.SQL_GROUPING_SORTING (
JOB_IDENT CHAR(9) NOT NULL,
JOB_TITLE VARCHAR(15) ,
MIN_SALARY DECIMAL(10,2),
MAX_SALARY DECIMAL(10,2),
PRIMARY KEY (JOB_IDENT));
CREATE TABLE DEPARTMENTS.SQL_GROUPING_SORTING (
DEPT_ID_DEP CHAR(9) NOT NULL,
DEP_NAME VARCHAR(15) ,
MANAGER_ID CHAR(9),
LOC_ID CHAR(9),
PRIMARY KEY (DEPT_ID_DEP));
CREATE TABLE LOCATIONS.SQL_GROUPING_SORTING (
LOCT_ID CHAR(9) NOT NULL,
DEP_ID_LOC CHAR(9) NOT NULL,
PRIMARY KEY (LOCT_ID,DEP_ID_LOC));
With the Db2 on Cloud Lite Plan
The Lite plan uses one database schema.
So the only schema you can use is the one that matches your user name. In your case this would be KZF72118
Create your tables with out a schema name, and they will be created in schema KZF72118.
You would need to use one of the other plans to remove this restriction

postgresql. uniqueness for two columns

I need to create unique index for table with two fields (email, alternative_email). It means one email address can be mentioned only one time in two columns. Also alternative email can be empty.
CREATE TABLE customers (
id serial PRIMARY KEY,
email VARCHAR (255) NOT NULL,
alternative_email VARCHAR (255) NOT NULL default ''
);
Data:
insert into customers (email, alternative_email)
values ('test#example.com', ''); - ok
insert into customers (email, alternative_email)
values ('test1#example.com', 'test#example.com');
Second row should not be inserted because alternative_email = 'test#example.com' already mentioned as email in first row.
How to create index to do this ?
You cannot create an index across two columns like that. What you need to do is change your design such that emails are all in one column in a different table.
So you could have a table called emails like:
CREATE TABLE emails (
id serial PRIMARY KEY,
email VARCHAR (255) NOT NULL UNIQUE,
);
Then have a many-to-many table that maps the customers to emails:
CREATE TABLE customer_emails (
customer_id INTEGER NOT NULL REFERENCES customers(id),
email_id INTEGER NOT NULL UNIQUE REFERENCES emails(id),
alternative boolean NOT NULL DEFAULT FALSE,
PRIMARY KEY (customer_id, email_id)
);
CREATE UNIQUE INDEX customer_email_idx ON customer_emails(customer_id, alternative);
This enforces that 2 different customers cannot reuse the same email address, that a customer can have at most one primary and one alternative email address, and the same email address cannot be used for both primary and alternative email addresses of the same customer.

PSQL enforce uniqueness, but within a subset of a table, not through the entire thing

I'm creating a database of assessments for courses using PostgreSQL.
I'd like assessment names to be unique within the course, but two courses can have assessments with the same name.
-- assessment contains the different assignments & labs that
-- students may submit their code to.
CREATE TABLE assessment (
id SERIAL PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL,
comments TEXT NOT NULL,
type ASSESSMENT_TYPE NOT NULL,
course_id SERIAL NOT NULL,
FOREIGN KEY (course_id) REFERENCES courses(id)
);
-- courses contains the information about a course. Since
-- the same course can run multiple times, a single course
-- is uniquely identified by (course_code, year, period)
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL, -- Unique within all courses. Wrong!
course_code VARCHAR(20) NOT NULL,
period PERIOD NOT NULL,
year INTEGER NOT NULL
);
Two main points:
Can I do this without changing the schema?
If so, is there a more idiomatic solution that may include schema changes?
1. Can I do this without changing the schema?
No, since you have multiple issues here.
Your assessments are globally unique by name and not within a course.
assessment.course_id has its own sequence which is useless (SERIAL is just INTEGER + SEQUENCE)
Table courses defines a column data type that does not exist: PERIOD (at least not up to version 11)
2. If so, is there a more idiomatic solution that may include schema changes?
A modified schema that should do what you want would look like this following:
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
course_code VARCHAR(20) NOT NULL,
period tstzrange NOT NULL
);
-- the following is required to build the proper unique constraint...
CREATE EXTENSION IF NOT EXISTS btree_gist;
-- the unique constraint: no two courses with same name at any point in time
ALTER TABLE courses
ADD CONSTRAINT idx_unique_courses
EXCLUDE USING GIST (name WITH =, period WITH &&);
CREATE TABLE assessment (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
comments TEXT NOT NULL,
type ASSESSMENT_TYPE NOT NULL,
course_id INTEGER NOT NULL REFERENCES courses(id),
UNIQUE (course_id, name)
);

References to multiple tables in PostgreSQL

I have many time series stored in a PostgreSQL database over multiple tables. I would like to create a table 'anomalies' which references to time series with particuliar behaviour, for instance a value that is exceptionally high.
My question is the following: what is the best way to link the entries of 'anomalies' with other tables?
I could create a foreign key in each table referencing to an entry in anomaly, but then it would be not so obvious to go from the anomaly to the entry referencing the anomaly.
The other possibility I see is to store the name of the corresponding table in the entries of anomalies, but it does not seem like a good idea, as the table name might change, or the table might get deleted.
Is there a more elegant solution to do this?
CREATE TABLE type_1(
type_1_id SERIAL PRIMARY KEY,
type_1_name TEXT NOT NULL,
unique(type_1_name)
)
CREATE TABLE type_1_ts(
date DATE NOT NULL,
value REAL NOT NULL,
type_1_id INTEGER REFERENCES type_1(type_1_id) NOT NULL,
PRIMARY KEY(type_1_id, date)
)
CREATE TABLE type_2(
type_2_id SERIAL PRIMARY KEY,
type_2_name TEXT NOT NULL,
unique(type_2_name)
)
CREATE TABLE type_2_ts(
date DATE NOT NULL,
value REAL NOT NULL,
state INTEGER NOT NULL,
type_2_id INTEGER REFERENCES type_2(type_2_id) NOT NULL,
PRIMARY KEY(type_2_id, date)
)
CREATE TABLE anomalies(
anomaly_id SERIAL PRIMARY_KEY,
date DATE NOT NULL,
property TEXT NOT NULL,
value REAL NOT NULL,
-- reference to a table_name and an entry id?
table_name TEXT
data_id INEGER
)
What I'd like to do at the end is to be able to do:
SELECT * FROM ANOMALIES WHERE table_name='type_1',
or simply list the data_type corresponding to the entries