Create tables with Many-to-One relation in Postgresql - sql

I am a newbie with Postgresql and database . I have the following table Shop
Create table Shop(
id integer ,
Name varchar(50),
Adress varchar(50) )
And I have a second table Product
Create table Product(
id integer ,
Name varchar(50),
Price float)
How to create a relation One-To-One between Product and Shop ?

Use a separate table, called a junction table or join table (and unfortunately has many other names)
CREATE TABLE Products_in_shop (
shop_id INTEGER,
product_id INTEGER
)
You can then JOIN them for specific queries, e.g. the products a specific shop carries:
SELECT p.Name
FROM Shop AS s
JOIN Products_in_shop AS pis ON pis.shop_id = s.id
JOIN Product AS p ON pis.product_id = p.id
WHERE s.Name = 'MyShop'

Related

Printing authors in descending order per sold copies per year

I have two tables
create table AUTHORS
(
id integer primary key,
name varchar(30)
)
create table BOOKS
(
id integer primary key,
name varchar(30),
year integer,
sold_copies integer,
author_id integer references AUTHORS (id)
)
How would I create a table with authors in descending order per sold copies of books per year in pgAdmin4 (PostgreSQL) ?
im a beginner and I am not sure how to go about this
I don't see why you would need to create a new table. A simple SELECT will do (maybe stored inside a view)
select a.id, a.name, b.year, sum(b.sold_copies) as total_copies
from author a
join books b on b.author_id = a.id
group by a.id, a.name, b.year
order by sum(b.sold_copies) desc;

Is there a way to select this name from more than one table?

I need to select the item name and the vendor name for each item that belongs to the vendor with a rating bigger than 4. And I can't find a way, I know it's something with joins but the 2 of them have the same column name.
CREATE TABLE venedors(
id int PRIMARY KEY,
name varchar2(20),
rating int)
CREATE TABLE items(
id int PRIMARY KEY,
name varchar2(20),
venedorId int references venedors(id))
If i understanded your problem.
Select items.name as itemName, venedors.name as vendorName
from items
inner join venedors
on items.venedorId = venedors.id
where venedors.rating > 4
If you want get all the vendors irrespective whether there are items associated with vendors or not, then try with left join as shown below:
Select v.name as vendorName, i.name as itemName
from venedors v
left join items i
on i.venedorId = v.id
where v.rating > 4

Sql query to find select customer that bought in the specific company address

Here is my table
CREATE TABLE Customer
(
ID CHAR(50),
Customer_FName CHAR(50),
Customer_Lname CHAR(50)
);
CREATE TABLE Buying
(
Customer_ID CHAR(50),
Product_ID CHAR(50),
Order_Time CHAR(50)
);
CREATE TABLE Product
(
ID CHAR(50),
Name CHAR(50),
Address CHAR(50)
);
I am trying to find all customers who bought a product with their company's address in 'Burwood' and list the customer's ID, names, product ID, product name and product address
Select
Buying.Customer_ID, Buying.Product_ID, Product.ID,
Product.Name, Customer.ID,
Customer.Customer_FName, Customer.Customer_Lname
from
((Buying
inner join
Product on Buying.Product_ID = Product.ID)
inner join
Customer on Buying.Customer_ID = Customer.ID)
where
Product.Address like '%Burwood%';
I want to combine three table but It shows 'no rows selected'.
I also give a sample data table
Any reason why you have chosen CHAR as the datatype for all columns of all tables? For CHAR based columns, DBs tend to pad the values up to the column width defined. That said, it is not why you are not getting result. You may want to check if during insert you are adding any extra space or non-printable characters in IDs resulting into failed inner joins.
I suggest change the fields to VARCHAR instead, validate your inserts and then query just as I demonstrated below. You will start getting result, as I am..
CREATE TABLE Customer (
ID varchar(50),
Customer_FName varchar(50),
Customer_Lname varchar(50)
);
CREATE TABLE Buying (
Customer_ID varchar(50),
Product_ID varchar(50),
Order_Time varchar(50)
);
CREATE TABLE Product (
ID varchar(50),
Name varchar(50),
Address varchar(50)
);
insert into customer values('10001', 'John', 'Smith');
insert into Buying values('10001', '772', '2016/09/01');
insert into Product values('772', 'Telephone', '22 Ave, Burwood');
select b.product_id, p.name, b.customer_id, c.customer_fname, c.customer_lname
from buying b
join product p on b.product_id = p.id
join customer c on b.customer_id = c.id
where lower(p.address) like '%burwood%'
Please try this, it works for me:
Select B.Customer_ID, B.Product_ID, P.ID, P.Name, C.ID, C.Customer_FName, C.Customer_Lname
from Buying B
INNER JOIN Product P ON B.Product_ID = P.ID
INNER JOIN Customer C ON B.Customer_ID = C.ID
WHERE P.Address LIKE '%Burwood%'
Try this:
SELECT C.*,B.*, P.*
FROM Customer C,Buying B, Product P
WHERE B.Product_ID=P.ID
AND B.Customer_ID=C.ID
AND P.Address LIKE '%Burwood%';

Join tables in sqlite with many to many

I have the following database schema:
create table people (
id integer primary key autoincrement,
);
create table groups (
id integer primary key autoincrement,
);
and I already have which people are members of which groups in a separate file (let's say in tuples of (person id, group id). How can I structure my database schema such that it's easy to access a person's groups, and also easy to access the members of a group? It is difficult and slow to read the tuples that I currently have, so I want this to be in database form. I can't have things like member1, member2, etc. as columns because the number of people in a group is currently unlimited.
Move your text file into a database table
CREATE TABLE groups_people (
groups_id integer,
people_id integer,
PRIMARY KEY(group_id, people_id)
);
And select all people that are a member of group 7
SELECT * FROM people p
LEFT JOIN groups_people gp ON gp.people_id = p.id
WHERE gp.groups_id = '7';
And select all the groups that person 5 is in
SELECT * FROM groups g
LEFT JOIN groups_people gp ON gp.groups_id = g.id
WHERE gp.people_id = '5';

Many-to-many relation filter

I need to filter my query with categories table which has many2many relation with another table. Is it possible to filter query with many2many relation?
Table res_partner has many2many field category_id relating to table res_partner_category.res_partner, or let's just say partners can have many categories. What I need is to filter res_partners table where it has category named 'business' or 'retail'. If it doesn't have any of these categories, it should not be shown.
Also there is another field in res_partner which is category_value_ids and has one2many relation with res_partners_category_value:
res_partner has following fields with relations:
category_id to res_partner_category (many2many)
category_value_ids to res_partner_category_value (one2many)
name (char)
res_partner_category has following fields with relations:
partner_ids to res_partner (many2many)
name (char)
res_partner_category_value has following fields with relations:
category_group_id to res_partner_category (many2one)
category_id to res_partner_category (many2one)
object_id tores_partner (many2one)
But if I try to use res_partner_category_value table in SQL query I get error that I can't use it in query.
So for example, if there are 4 partners with these categories:
first: categ1, categ2, business
second: retail
third: retail, business
fourth: categ1, categ2
The query should return first, second and third partners.
One person told me it's not possible to filter like this with many2many relation. So I wonder is it really not possible or just complicated?
EDIT:
I found one more table called res_partner_category_rel. I didn't see it, because in Openerp administration interface, where you can see all objects of database, that table is not shown. You can only see it directly through database.
So I was confused by this "missing" table:
res_partner_category_rel:
partner_id (many2one)
category_id (many2one)
Setup
This is the test case you should have provided:
CREATE TABLE partner (
partner_id serial PRIMARY KEY
, partner text
);
INSERT INTO partner (partner) VALUES
('partner1')
, ('partner2')
, ('partner3')
, ('partner4')
;
CREATE TABLE category (
category_id serial PRIMARY KEY
, category text
);
INSERT INTO category (category) VALUES
('categ1')
, ('categ2')
, ('business')
, ('retail')
;
CREATE TABLE partner_category (
partner_id int REFERENCES partner(partner_id)
, category_id int REFERENCES category(category_id)
, CONSTRAINT cat_pk PRIMARY KEY (partner_id, category_id)
);
INSERT INTO partner_category (partner_id, category_id) VALUES
(1,1), (1,2), (1,3)
, (2,4)
, (3,3), (3,4)
, (4,1), (4,2);
Solution
One way:
SELECT p.*
FROM partner p
WHERE EXISTS (SELECT FROM partner_category pc WHERE pc.partner_id = p.partner_id AND pc.category_id = 3)
OR EXISTS (SELECT FROM partner_category pc WHERE pc.partner_id = p.partner_id AND pc.category_id = 4)
ORDER BY p.partner_id;
Another:
SELECT p.*
FROM (SELECT partner_id FROM partner_category WHERE category_id = 3) pc1
FULL JOIN (SELECT partner_id FROM partner_category WHERE category_id = 4) pc2 USING (partner_id)
JOIN partner p USING (partner_id)
ORDER BY p.partner_id;
fiddle
Old sqlfiddle
The second one assumes unique (partner_id, category_id) in partner_category.
As you already noticed, the many2one category_id is not represented in the database as a table field, but as a table relating Partners and Categories.
The SQL you need could look like this:
SELECT p.*
FROM res_partner p
INNER JOIN res_partner_category_rel rel ON p.id = rel.partner_id
INNER JOIN res_partner_category c ON rel.category_id = c.id
WHERE c.id in (3,4)
If you want to do the filter in the python object, the usual searchcall should work:
list_ids = partner_model.search(cr, uid, [('category_id', 'in', [3,4])])
As a bonus, since Categories are organized in a tree, you could get those categories and all their children using:
list_ids = partner_model.search(cr, uid, [('category_id', 'child of', [3,4])])