How to relate tables SQL - sql

I have three tables and i want to relate them, but i don't know what im doing wrong. If the way that im thinking is bad, can you correct me also?
I have clients table with Primary key as ID_c column,
create table clients
(
id_c INTEGER not null,
name VARCHAR2(20),
age INTEGER,
address VARCHAR2(20),
Primary key (id_c)
);
also i have products with primary key as ID_p column.
create table PRODUCTS
(
id_p NUMBER not null,
name_product VARCHAR2(30),
price NUMBER,
duration NUMBER,
primary key (id_p)
);
and now i create third
create table TRANSACTIONS
(
id_t NUMBER not null,
id_c NUMBER not null,
id_p NUMBER not null
primary key (ID_t),
foreign key (ID_c) references CLIENTS (ID_c),
foreign key (ID_p) references PRODUCTS (ID_p)
);
and now i want to see all records that are connected, so im trying to use that:
select * from transactions join clients using (id_c) and join products using (id_p);
but only what works is
select * from transactions join clients using (id_c);
is it relational database or im making something too easy, and too primitive? How can i do that to connect everything?

try this
select *
from transactions
inner join clients on transactions.id_c = clients.id_c
inner join products on transactions.id_p = products.id_p;

Are you just trying to join?
select * from transactions a
join clients b on a.id_c = b.id_c
join products c on a.id_p = c.id_p

If you want to join 3 tables, just write:
SELECT * FROM TRANSACTIONS t JOIN client c on t.id_c = c.id_c JOIN PRODUCTS p on t.id_p = p.id_p

Related

how Inner join work on two foreign key from single table

I am working on Bus route management system , I made two table first one is Cities and second one is route have following queries
CREATE TABLE Cities
(
ID NUMBER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1) PRIMARY KEY,
Name Varchar(30) not null,
)
CREATE TABLE route
(
ID NUMBER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1) PRIMARY KEY,
Name Varchar(30) not null,
from NUMBER not null,
to NUMBER NOT NULL,
CONSTRAINT FROM_id_FK FOREIGN KEY(from) REFERENCES Cities(ID),
CONSTRAINT TO_id_FK FOREIGN KEY(to) REFERENCES Cities(ID),
)
i am joining the table through inner join
select CITIES.Name
from CITIES
inner join ROUTES on CITIES.ID=ROUTES.ID
but it show single column as
Name
-----------
but i want result as
from | to
------------------------
what is possible way to do this using inner join
I suspect you need something like the following:
select r.Name, cs.Name SourceCity, cd.Name DestinationCity
from routes r
join cities cs on cs.id = r.from
join cities cd on cd.id = r.to
Hope is working for you
select CITIES.Name,ROUTES.from,ROUTES.to
from CITIES inner join ROUTES on CITIES.ID=ROUTES.ID

What is the most efficient way of joining tables of different dimensions?

I have the following schema:
CREATE TABLE products (
id BIGSERIAL NOT NULL,
created_at_timestamp TIMESTAMP NOT NULL DEFAULT NOW(),
last_update_timestamp TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (id)
);
CREATE TABLE product_names (
product_id BIGINT NOT NULL,
language TEXT NOT NULL,
name TEXT NOT NULL,
PRIMARY KEY (product_id, language),
FOREIGN KEY (product_id) REFERENCES products (id)
);
CREATE TABLE product_summaries (
product_id BIGINT NOT NULL,
language TEXT NOT NULL,
summary TEXT NOT NULL,
PRIMARY KEY (product_id, language),
FOREIGN KEY (product_id) REFERENCES products (id)
);
And I want to select all Products.
However as you can see a Product contains a list of names and summaries (per language).
I can retrieve all Products
SELECT * FROM products
And then iterate all the rows (in this case in Kotlin), and then request the names and summaries:
SELECT * FROM product_names WHERE product_id = $id
And
SELECT * FROM product_summaries WHERE product_id = $id
However, this seems inefficient, since I am making 3 separate queries to the database.
I though of using JOINs to get all of this with one query, but then I get multiple repeated rows for each product_names and product_summaries entry.
So in the end, is there a better way of requesting all this data in one query?
You definitely don't want to do multiple queries and then iterate over them in the code. That's horribly inefficient. When you do the second JOIN, you need to include language in the JOIN. That should keep you from getting duplicate rows. This should give you one row for each unique combination of [products.id, product_names.language]
SELECT
products.id
,products.created_at_timestamp
,products.last_update_timestamp
,product_names.name
,product_summaries.summary
,product_names.language
FROM
products
INNER JOIN
product_names ON product_names.product_id = products.id
INNER JOIN
product_summaries ON product_summaries.product_id = products.id
AND product_summaries.language = product_names.language
I've found a way of doing it:
SELECT * FROM products as p INNER JOIN
(SELECT json_agg(product_names) as names, product_id FROM product_names GROUP BY product_id) as tb_names ON tb_names.product_id = p.id
INNER JOIN
(SELECT json_agg(product_summaries) as summaries, product_id FROM product_summaries GROUP BY product_id) as tb_summaries ON tb_summaries.product_id = p.id
returns:
1 | 2018-07-20 09:36:21.56904 | 2018-07-20 09:36:21.56904 | [{"product_id":1,"language":"EN","name":"lol"},
{"product_id":1,"language":"DE","name":"lel"}] | 1 [{"product_id":1,"language":"EN","summary":"deded"},
{"product_id":1,"language":"DE","summary":"rererere"},
{"product_id":1,"language":"FR","summary":"jejejeje"}] | 1
Basically I'm converting the multi-dimensional tables to JSON :)
Postgres is amazing!

Multi-table, multi-row SQL select

How would I list all of the info about a freelancer given the schema below? Including niche, language, market, etc. The issue I am having is that every freelancer can have multiple entries for each table. So, how would I do this? Is it even possible using SQL or would I need to use my primary language (golang) for this?
CREATE TABLE freelancer (
freelancer_id SERIAL PRIMARY KEY,
ip inet NOT NULL,
username VARCHAR(20) NOT NULL,
password VARCHAR(100) NOT NULL,
email citext NOT NULL UNIQUE,
email_verified int NOT NULL,
fname VARCHAR(20) NOT NULL,
lname VARCHAR(20) NOT NULL,
phone_number VARCHAR(30) NOT NULL,
address VARCHAR(50) NOT NULL,
city VARCHAR(30) NOT NULL,
state VARCHAR(30) NOT NULL,
zip int NOT NULL,
country VARCHAR(30) NOT NULL,
);
CREATE TABLE market (
market_id SERIAL PRIMARY KEY,
market_name VARCHAR(30) NOT NULL,
);
CREATE TABLE niche (
niche_id SERIAL PRIMARY KEY,
niche_name VARCHAR(30) NOT NULL,
);
CREATE TABLE medium (
medium_id SERIAL PRIMARY KEY,
medium_name VARCHAR(30) NOT NULL,
);
CREATE TABLE format (
format_id SERIAL PRIMARY KEY,
format_name VARCHAR(30) NOT NULL,
);
CREATE TABLE lang (
lang_id SERIAL PRIMARY KEY,
lang_name VARCHAR(30) NOT NULL,
);
CREATE TABLE freelancer_by_niche (
id SERIAL PRIMARY KEY,
niche_id int NOT NULL REFERENCES niche (niche_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_medium (
id SERIAL PRIMARY KEY,
medium_id int NOT NULL REFERENCES medium (medium_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_market (
id SERIAL PRIMARY KEY,
market_id int NOT NULL REFERENCES market (market_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_format (
id SERIAL PRIMARY KEY,
format_id int NOT NULL REFERENCES format (format_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
CREATE TABLE freelancer_by_lang (
id SERIAL PRIMARY KEY,
lang_id int NOT NULL REFERENCES lang (lang_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id)
);
SELECT *
FROM freelancer
INNER JOIN freelancer_by_niche USING (freelancer_id)
INNER JOIN niche USING (niche_id)
INNER JOIN freelancer_by_medium USING (freelancer_id)
INNER JOIN medium USING (medium_id)
INNER JOIN freelancer_by_market USING (freelancer_id)
INNER JOIN market USING (market_id)
INNER JOIN freelancer_by_format USING (freelancer_id)
INNER JOIN format USING (format_id)
INNER JOIN freelancer_by_lang USING (freelancer_id)
INNER JOIN lang USING (lang_id);
And if you want to lose the unnecessary attributes from join tables like freelancer_by_format, then you can do this
SELECT a.ip, a.username, a.password, a.email, a.email_verified,
a.fname, a.lname, a.phone_number, a.address, a.city,
a.state, a.zip, a.country,
b.niche_name, c.medium_name, d.market_name, e.format_name, f.lang_name
FROM freelancer a
INNER JOIN freelancer_by_niche USING (freelancer_id)
INNER JOIN niche b USING (niche_id)
INNER JOIN freelancer_by_medium USING (freelancer_id)
INNER JOIN medium c USING (medium_id)
INNER JOIN freelancer_by_market USING (freelancer_id)
INNER JOIN market d USING (market_id)
INNER JOIN freelancer_by_format USING (freelancer_id)
INNER JOIN format e USING (format_id)
INNER JOIN freelancer_by_lang USING (freelancer_id)
INNER JOIN lang f USING (lang_id);
And if you want to change the column names, for example change "market_name" to just "market", then you go with
SELECT a.ip, ... ,
d.market_name "market", e.format_name AS "format", ...
FROM ...
Remarks
In your join tables (for example freelancer_by_niche) there is not UNIQUE constraint on freelancer_id, which means that you could have the same freelancer in multiple markets (that's ok and probably intended).
But then you also don't have a UNIQUE constraint on both attributes (freelancer_id, niche_id), which means that every freelancer could be in the SAME niche multiple times. ("Joe is in electronics. Three times").
You could prevent that by making (freelancer_id, niche_id) UNIQUE in freelancer_by_niche.
This way you would also not need a surrogate (artificial) PRIMARY KEY freelancer_by_id (id).
So what could go wrong then?
For example imagine the same information about a freelancer in the same niche three times (the same data parts of the row three times):
freelancer_by_niche
id | freelancer_id | niche_id
1 | 1 | 1 -- <-- same data (1, 1), different serial id
2 | 1 | 1 -- <-- same data (1, 1), different serial id
3 | 1 | 1 -- <-- same data (1, 1), different serial id
Then the result of the above query would return each possible row three (!) times with the same (!) content, because freelancer_by_niche can be combined three times with all the other JOINs.
You can eliminate duplicates by using SELECT DISTINCT a.id, ... FROM ... above with DISTINCT.
What if you get many duplicate rows, for example 10 data duplicates in each of the 5 JOIN tables (freelancer_by_niche, freelancer_by_medium etc)? You would get 10 * 10 * 10 * 10 * 10 = 10 ^ 5 = 100000 duplicates, which all have the exact same information.
If you then ask your DBMS to eliminate duplicates with SELECT DISTINCT ... then it has to sort 100000 duplicate rows per different row, because duplicates can be detected by sorting only (or hashing, but never mind). If you have 1000 different rows for freelancers on markets, niches, languages etc, then you are asking your DBMS to SORT 1.000 * 100.000 = 100.000.000 rows to reduce the duplicates down to the unique 1000 rows.
That is 100 million unnecessary rows.
Please make UNIQUE (freelancer_id, niche_id) for freelancer_by_niche and the other JOIN tables.
(By data duplicates i mean that the data (niche_id, freelancer_id) is the same, and only the id is auto incremented serial.)
You can easily reproduce the problem by doing the following:
-- this duplicates all data of your JOIN tables once. Do it many times.
INSERT INTO freelancer_by_niche
SELECT (niche_id, freelancer_id) FROM freelancer_by_niche;
INSERT INTO freelancer_by_medium
SELECT (medium_id, freelancer_id) FROM freelancer_by_medium;
INSERT INTO freelancer_by_market
SELECT (market_id, freelancer_id) FROM freelancer_by_market;
INSERT INTO freelancer_by_format
SELECT (format_id, freelancer_id) FROM freelancer_by_format;
INSERT INTO freelancer_by_lang
SELECT (lang_id, freelancer_id) FROM freelancer_by_lang;
Display the duplicates using
SELECT * FROM freelancer_by_lang;
Now try the SELECT * FROM freelancer INNER JOIN ... thing.
If it still runs fast, then do all the INSERT INTO freelancer_by_niche ... again and again, until it takes forever to calculate the results.
(or you get duplicates, which you can remove with DISTINCT).
Create UNIQUE data JOIN tables
You can prevent duplicates in your join tables.
Remove the id SERIAL PRIMARY KEY and replace it with a multi-attribute PRIMARY KEY (a, b):
CREATE TABLE freelancer_by_niche (
niche_id int NOT NULL REFERENCES niche (niche_id),
freelancer_id int NOT NULL REFERENCES freelancer (freelancer_id),
PRIMARY KEY (freelancer_id, niche_id)
);
(Apply this for all your join tables).
The PRIMARY KEY (freelancer_id, niche_id) will create a UNIQUE index.
This way you cannot insert duplicate data (try the INSERTs above, the will be rejected, because the information is already there once. Adding another time will not add more information AND would make your query runtime much slower).
NON-unique index on the other part of the JOIN tables
With PRIMARY KEY (freelancer_id, niche_id), Postgres creates a unique index on these two attributes (columns).
Accessing or JOINing by freelancer_id is fast, because it's first in the index. Accessing or JOINing into freelancer_by_niche.niche_id will be slow (Full Table Scan on freelancer_by_niche).
Therefore you should create an INDEX on the second part niche_id in this table freelancer_by_niche, too.
CREATE INDEX ON freelancer_by_niche (niche_id) ;
Then joins into this table on niche_id will also be faster, because they are accelerated by an index. The index makes queries faster (usually).
Summary
You have a very good normalized database schema! It's very good. But small improvements can be made (see above).

SQL get all entries by ids

I have 3 tables roughly like below:
create table user(
id integer primary key
)
create table post(
id integer primary key,
author integer,
foreign key (author) references user(id)
)
create table user_following(
id integer primary key,
follower integer,
followee integer,
foreign key (follower) references user(id),
foreign key (followee) references user(id)
)
these tables were created by ORM framework, I want to use raw SQL to get all posts by a user's followee, which can be multiple users. Can I do it in SQL?
If you know the follower's ID, the below statement will conduct a join and get the follower's followees' posts. You can replace the number 3 with any user id.
SELECT * FROM user_following AS a
JOIN post AS b ON a.followee = b.author
WHERE a.follower=3;
Something like this?
select p.*
from post p
join user_following uf on p.author = uf.followee
where uf.follower = 123;
select posts.*
from post posts
inner join [user] u_followee on u_followee.id = posts.author
inner join user_following ufo on ufo.followee = u_followee.id
inner join [user] u_follower on ufo.follower = u_follower.id
where u_follower.id = #USER_ID_WHOSE_FOLLOWEE_POSTS_REQUIRED

How to create relationship between two non primary key entity in SQL Server

I have few tables where I need to link Patient card ID (PID) of table patient where primary key is patient_id with the PID field of other tables... how can I do that? help!
you can join them like
SELECT *
FROM [Patient] p
INNER JOIN [OtherTable] ot
ON p.pid = ot.patient_id;
You can use Foreign Keys
CREATE TABLE T
(
any_primary_key INT PRIMARY KEY,
[other attributes],
patient_id,
FOREIGN KEY (patiend_id) REFERENCES Patients.patient_id
)
Where Patients is a table that has the original patient_id which has to be declared as unique.