How to do a query with multiple foreign keys pointing to one table? - sql

I have a PostgreSQL database with two tables (person, item). The person table consists of id, name, and let‘s say 5 item columns with foreign keys referencing to the item table. The item table consists of id, name and description.
I want to do a query now that list the person.id, person.name and the 5 item.name. How can I achieve this? I know something with JOIN but I don‘t get it right now.

You have a problem with your data model. You should not be storing lists of items in separate columns. There are multiple alternatives. The typical solution is a separate table with one row per person and item. You can also store the items as arrays or JSON.
But to answer your question, you need multiple joins:
select p.*, i1.name as item_name_1, i2.name as item_name_2
from person p left join
items i1
on p.item_id_1 = i1.id left join
items i2
on p.item_id_2 = i1.id left join
. . . -- and so on

Related

SQL select with three tables

Hi guys I'm new with databases and I'm trying to make a query where I join 3 tables. I could make it and I want to clean up the result. I want to know how can I delete the column "pin" from users table and maybe some "ids" columns.
Select * from "wish-list"
Join products
On "wish-list".id = products.holiday_id
Join users
On "wish-list".user_id = users.id
Where "wish-list".id = 1
You need to specify which columns you really need in your output. At the moment you are using
SELECT * which outputs all columns of all joined tables.
Here is what it should look like:
SELECT holiday, products.description, users.pin FROM "wish-list"
JOIN products ON "wish-list".id = products.holiday_id
JOIN users ON "wish-list".user_id = users.id
WHERE "wish-list".id = 1
It's important that you reference all columns which are not your main entity (here wish-list) with tablename.column (products.description and not only description). It will work without referencing strictly but only if the column name is unique in your query.
Furthermore you can rename columns. This is useful for example if you want to get the id's of the product table and the wish-list table.
SELECT product.id AS product_id, id AS wishlist_id FROM "wish-list"
...
Hope that helps!

Access SQL Query on same table

I have two tables: one called EMP_Names which simply stores ID and Employee_Name and another table called EMP_Main which stores the main data and which refers to EMP_Names via IDs. Amongst other fields EMP_Main has fields called Technician_Name_ID and Leader_Name_ID which is related to EMP_Names. My problem is this: how can i run a query where both Technician_Name_ID and Leader_Name_ID resolve to Names? In other words both ID fields refer to the same EMP_Names.ID but I can only establish one relationship between the two tables.
Don't know if I'm clear because it's difficult to explain ...
You can use join but you need multiple joins.
select em.*, ent.name as technician, enl.name as leader
from (emp_main as em left join
emp_names as ent
on em.technician_name_id = ent.id
) left join
emp_names as enl
on em.leader_name_id = enl.id;
These are left joins in case the fields are not populated for all rows.

Multiple Many-to-many bi-directional self-inner-joins without repeating whole query

I have a data model such that items can have many-to-many relationships with other items in the same table using a second table to define relationships. Let's call the primary table items, keyed by item_id and the relationships table item_assoc with columns item_id and other_item_id and assoc_type. Generally, you might use a union to pick up on relationships that may be defined in either direction in the item_assoc table, but you would wind up repeating other parts of the same query just to be sure to pick up associations defined in either direction.
Let's say that you're trying to put together a fairly complex query similar to the following where you want to find a list of items that have related items that COULD have associated cancellation items, but select those that do not have cancellation items:
select
orig.*
from items as orig
join item_assoc as orig2related
on orig.item_id = orig2related.item_id
join items as related
on orig2related.other_item_id = related.item_id
and orig2related.assoc_type = 'Related'
left join item_assoc as related2cancel
on related.item_id = related2cancel.item_id
left join items as cancel
on related2cancel.other_item_id = cancel.item_id
and related2cancel.assoc_type = 'Cancellation'
where cancel.item_id is null
This query obviously only picks up items whose relationships are defined in one direction. For a less complex query, I might solve this by adding a union at the bottom for every permutation of the reverse relationships, but I think that would make the query unnecessarily long and hard to understand.
Is there a way I can define both directions of each relationship without repeating the other parts of the query?
A UNION within item_assoc could help. Assuming you have a DB without a WITH clause you would have to define a view
CREATE VIEW bidirec_item_assoc AS
(
SELECT item_id, other_item_id, assoc_type, 1 as direction FROM item_assoc
UNION
SELECT other_item_id, item_id, assoc_type, 2 as direction FROM item_assoc
)
You can now use bidirec_item_assoc in your queries where you have used items_assoc before.
Edited Out: You could add columns for direction and relationtype, of course
Simplify, simplify, simplify: Don't involve tables in the query that aren't needed.
The following query should be equivalent to your sample query and more expressive of your intent:
select i.*
from items i
where not exists ( select *
from item_assoc r
join item_assoc c on c.item_id = r.item_id
and c.assoc_type = 'Cancellation'
where r.item_id = i.item_id
and r.assoc_type = 'Related'
)
It should select the set of items that aren't related to an item that has been cancelled. There's not need to join against the items table 3 times.
Further, your original query will have duplicate rows: every row in the first item table (orig) will be duplicated once for every related item.

sqlite, counting foreign key references

I have two tables, one that defines lists and another that defines items in the lists. When i run this i only get lists that have items referencing them. i really need to get a result for all rows in the lists table and a count of how many rows in the items table reference each list.
SELECT name, COUNT(items.listId) as itemCount
FROM lists
INNER JOIN items
ON lists._id = items.listId
GROUP BY items.listId
any help would be much appreciated.
Try changing your INNER JOIN to a LEFT OUTER JOIN, and change your GROUP BY to lists._id. I didn't test this!

SQL Join 2 tables

I have two tables one named Person, which contains columns ID and Name and the second one, named Relation, which contains two columns, each of which contains an ID of a Person. It's about a relation between customer and serviceman. I'd like to Join these two tables so that I'll have names of people in every relation. Is it possible to write this query with some kind of joining?
EDIT::
I must do something wrong, but it's not working. I had tried a lot of forms of so looking queries, but I had been only getting one column or some errors. It's actually the school task, I have it already done (with different JOIN query). Firstly I had been trying to do this, but I'd failed: It seems to be very common situation, so I don't know why it's too complicated for me..
Here are my tables:
CREATE TABLE Oprava..(Repair) (
KodPodvozku INTEGER PRIMARY KEY REFERENCES Automobil(KodPodvozku),
IDzakaznika..(IDcustomer) INTEGER REFERENCES Osoba(ID),
IDzamestnance..(IDemployee) INTEGER REFERENCES Osoba(ID)
);
CREATE TABLE Osoba..(Person) (
ID INTEGER CONSTRAINT primaryKeyOsoba PRIMARY KEY ,
Jmeno..(Name) VARCHAR(256) NOT NULL,
OP INTEGER UNIQUE NOT NULL
);
It's in Czech, but the words in brackets after ".." are english equivalents.
PS: I am using Oracle SQL.
Assuming your tables are:
persons: (id, name)
relations: (customer_id, serviceman_id)
Using standard SQL:
SELECT p1.name AS customer_name,
p2.name AS serviceman_name
FROM persons p1
JOIN relations ON p1.id=relations.customer_id
JOIN persons p2 ON relations.serviceman_d=p2.id;
Further explanation
The join creates the following table:
p1.id|p1.name|relations.customer_id|relations.serviceman_id|p2.id|p2.name
Where p1.id=relations.customer_id, and p2.id=relations.serviceman_id. The SELECT clause chooses only the names from the JOIN.
Note that if all the ids from relations are also in persons, the result size would be exactly the size of the relations table. You might want to add a foreign key to verify that.
SELECT *
FROM Relation
INNER JOIN Person P1
ON P1.ID = Relation.FirstPersonID
INNER JOIN Person P2
ON P2.ID = Relation.SecondPersonID
SELECT p1.name AS customer, p2.name AS serciveman
FROM person p1, person p2, relation
WHERE p1.id=relation.customerid AND p2.id=relation.servicemanid
Person(ID, Name)
Relation(ID)
You don't mention the other columns that relation contains but this is what you need:
Select name
from Person as p
join Relation as r
on p.ID = r.ID
This is an INNER JOIN as are most of the other answers here. Please don't use this until you understand that if either record doesn't have a relationship in the other table it will be missing from the dataset (i.e. you can lose data)
Its very important to understand the different types of join so I would use this as an opportunity.