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.
Related
I am trying to join two tables together using UNION (although im not sure that is the best option) there are technically two related columns however they don't have the same name so i'm assuming that isn't an option here is my query:
SELECT title, type, release_date FROM pictures
UNION
SELECT name, residence, NULL as Col3 FROM actor
ORDER BY release_date ASC;
It is only printing out the pictures columns from this? Thank you for any help in advance.
To relate two tables you could use some foreign key or a third table in the case of beign a many-to-many relation, you should use one of the join options, for example:
Imagine that exists a table that relate actor and pictures, called actor_pictures.
Image that we will relate the tables by id (it could be another one, and it doesn't have to have the same name).
You could do this:
SELECT * FROM actor_pictures ap
JOIN actor a ON ap.actor_id = a.id
JOIN pictures p ON ap.pictures_id = p.id
ORDER BY p.release_date ASC
Read this: https://www.w3schools.com/sql/sql_join.asp
I'm creating a data warehouse for a healthcare company. They have separate databases for different hospitals which contain tables on patients,their insurance,etc and PK is unique only within one hospital DB. When merged, I'm supposed to create a Master Patient Table, a Master Insurance Company table,etc that combines duplicate data into one record(eg. by comparing name and SSN fields for patients).
Any suggestions on how to do this merge, and create correct FK references in the new tables? A record in the Patient table needs to have a correct reference to an insurance company in the Insurance table. Any help or general pointers is appreciated!
Load the data from the first hospital (H1) into the warehouse. Then, move in the patient data from the second hospital (H2):
insert into P1.Patients( pid, ... )
select P2.pid, P2.this, P2.that, ...
from H2.Patients P2
left join H1.Patients P1
on P1.ssn = P2.ssn
where P1.pid is null;
Now you have added the P2 patients that were not already in the P1 patient table but retained the P1 patient ids of those already there. (You may have to handle collisions.) Then join the H2 insurance table with the H2 patient table to get the SSN joining with H1 patient table to get the H1.PatientID (pid).
insert into H1.Insurance( pid, ...)
select P1.pid, I2.this, I2.that,... -- To get H1's pid for H2's patients...
from H2.Insurance I2 -- Join the 2nd hospital's insurance table
join H2.Patients P2 -- ...with its patient table
on P2.pid = I2.pid -- ...based on its existing patient ID value.
join H1.Patients P1 -- Now you can join with first hospitals patient table
on P1.ssn = P2.ssn -- ...using SSN from 2nd hospital's patient table
where anything_else;
Repeat for other tables, using P1.pid to replace all uses of P2.pid.
The other answer just seems horribly inefficient. Instead of doing so many joins I would have a SELECT statement FROM H1.P P1 and H2.P P2 where P1.SSN==P2.SSN and insert this into H1. Then have a select for Insurance FK,Guarantor FK and whatever else you have on this result and left join it to this table. Do something similar for Insurance tables. Then select records where Insurance ID matches Insurance FK in patient and update them with new surrogate keys..
Although I would like someone with more experience taking on this question as well..
I am creating a database based on a sporting game to store matches and each player involved in each match. I am having trouble resolving a many to many relationship. I currently have the following tables:
Player
id
name
Match
id
date
PlayerMatch
player_id
match_id
home_team
goals_for
goals_against
There will always be a minimum of two players in a match. Is this the best design for this approach?
I would recommend a sticking with a many to many relationship. This allows you to change the specifications of how many players you can have in a game easily while not complicating the data model much.
Player
id
name
Match
id
date
PlayerMatch
player_id
match_id
is_home
goals_for
goals_against
Foreign key from PlayerMatch to Player
Foreign key from PlayerMatch to Match
--All the matches a player has played in.
SELECT m.*
FROM Player p
JOIN PlayerMatch pm
ON p.id = pm.player_id
JOIN Match m
ON m.id = pm.match_id
WHERE p.id = /*your player Id*/
--All the players in a match
SELECT p.*
FROM Match m
JOIN PlayerMatch pm
ON m.id = pm.match_id
JOIN Player p
ON p.id = pm.player_id
WHERE m.id = /*your match Id*/
--player information for a single match.
SELECT pm.*
FROM Player p
JOIN PlayerMatch pm
ON p.id = pm.player_id
JOIN Match m
ON m.id = pm.match_id
WHERE p.id = /*your player Id*/
AND m.id = /*your match Id*/
That is a valid option, though I would suggest a naming convention where you use the same column name in both tables (i.e. use match_id in both Match and PlayerMatch; same for player_id). This helps make your SQL a bit more clear and when doing joins in some databases (MySQL) you can then use the 'using (col1, col2, ...)' syntax for the joins.
I wouldn't use the many-to-many relationship, I would do like this:
Player
id
name
Match
id
home_player_id
guest_player_id
date
goals_home_player
goals_guest_player
I think I'd try to model the match first & then see what happens with the table design :
Match
-------------
match_Id
player1_Id
player2_Id
player1_Goals
player2_Goals
Where player1_Id and Player2_Id are both foreign keys onto the Player table
Player
---------
Id
Name
By convention player1 would always be the home team
then you would query it like
Select p1.name as player1_Home, p2.name as player2_away,
matchId,
player1_Goals as homeGoals, player2_Goals as awayGoals
from Match m
inner join Player p1 on p1.id = m.Player1_Id
inner join Player p2 on p2.id = m.Player2_Id
This sort of data relationship is not at all unnatural. To set it up, just ask yourself two questions:
Do players have more than one match?
Do matches have more than one player?
If the answer is yes to both, then you have a many-to-many relationship and these are not at all uncommon. Their implementation is only slightly more complicated. In a one-to-many relationship, you'd hold a foreign key to a list of records in some table. As it happens, this is still how it works in many-to-many relationships, except that both the Players and the Matches table will need a foreign key to some list of records.
This list is called the Bridge Table. So you'll need to use a total of three tables to descrive the relationship
Players
-------
player_id
<player attribute columns, eg last_name, first_name, goals_scored, etc.>
Player_Match
------------
player_id
match_id
Matches
-------
match_id
<a list of columns that are match attributes, eg. match date, etc.>
The table in the middle of the diagram above is called a bridge table, and it does nothing more than map players to matches, and it also maps matches to a list of players. Often, bridge tables have only 2 columns, each representing a foreign key to one of the bridged tables. There is no need for a primary key in a bridge table, and if there is not one, it means that a player can have more than one of the same match. If a player can have only one of one kind of match, then make the primary key for each row of the bridge table a composite key on both of the columns.
In database design, normalization is a highly desirable relational goal because it provides a database with the greatest possible flexibility and the lowest amount of redundancy. To normalize, ask yourself if the data you want to put in a table is -really- an actual attribute of the object described by the primary key. For example, is the home_team an actual attribute of the match. I would say no, it is not. In this case, you should replace home_team in your PlayerMatch table with a foreign key to a Teams table. In your Matches table, you ought to have two columns. One for a home team foreign key, and one for the away team key. The teams are not actual attributes of a match and so to normalize the Match table, you'd want to put those data in tables of their own.
Agree with M Hagopian, the op schema looks like a good start.
I use three tables to get to the final result. They are called project_board_members, users and project_team.
This is the query:
SELECT `project_board_members`.`member_id`,
`users`.`name`,
`users`.`surname`,
`users`.`country`,
`project_team`.`tasks_completed`
FROM `project_board_members`
JOIN `users`
ON (`users`.`id` = `project_board_members`.`member_id`)
JOIN `project_team`
ON (`project_team`.`user_id` = `project_board_members`.`member_id`)
WHERE `project_board_members`.`project_id` = '5'
You can ignore last line because it just points to the project I'm using.
Table project_board_members holds three entries and have structure like:
id,
member_id,
project_id,
created_at;
I need to get member_id from that table. Then I join to users table to get name, surname and country. No problems. All works! :)
After that, I needed to get tasks_completed for each user. That is stored in project_team table. The big unexpected thing is that I got four entries returned and the big what-the-f*ck is that in the project_board_members table are only three entries.
Why is that so? Thanks in advice!
A SQL join creates a result set that contains one row for each combination of the left and right tables that matches the join conditions. Without seeing the data or a little more information it's hard to say what exactly is wrong from what you expect, but I'm guessing it's one of the following:
1) You have two entries in project_team with the same user_id.
2) Your entries in project_team store both user_id and project_id and you need to be joining on both of them rather than just user_id.
The table project_board_members represent what is called in the Entity-Relationship modelling world an "associative entity". It exists to implement a many-to-many relationship (in this case, between the project and user entities. As such it is a dependent entity, which is to say that the existence of an instance of it is predicated on the existence of an instance of each of the entities to which it refers (a user and a project).
As a result, the columnns comprising the foreign keys relating to those entities (member_id and project_id) must be form part or all of the primary key.
Normally, instances of an associative entity are unique WRT the entities to which it relates. In your case the relationship definitions would be:
Each user is seated on the board of 0-to-many projects;
Each project's board is comprise of 0-to-many users
which is to say that a particular user may not be on the board of a particular project more than once. The only reason for adding other columns (such as your id column) to the primary key would be if the user:project relationship is non-unique.
To enforce this rule -- a user may sit on the board a particular project just once -- the table schema should look like this:
create table project_board_member
(
member_id int not null foreign key references user ( user_id ) ,
project_Id int not null foreign key references project ( project_id ) ,
created_at ...
...
primary key ( member_id , project_id ) ,
)
}
The id column is superfluous.
For debugging purposes do
SELECT GROUP_CONCAT(pbm.member_id) AS member_ids,
GROUP_CONCAT(u.name) as names,
GROUP_CONCAT(u.surname) as surnames,
GROUP_CONCAT(u.country) as countries,
GROUP_CONCAT(pt.tasks_completed) as tasks
FROM project_board_members pbm
JOIN users u
ON (u.id = pbm.member_id)
JOIN project_team pt
ON (pt.user_id = pbm.member_id)
WHERE pbm.project_id = '5'
GROUP BY pbm.member_id
All the fields that list multiple entries in the result are messing up the rowcount in your resultset.
To Fix that you can do:
SELECT pbm.member_id
u.name,
u.surname,
u.country,
pt.tasks_completed
FROM (SELECT
p.project_id, p.member_id
FROM project_board_members p
WHERE p.project_id = '5'
LIMIT 1
) AS pbm
JOIN users u
ON (u.id = pbm.member_id)
JOIN project_team pt
ON (pt.user_id = pbm.member_id)
I'm not sure how to write this query in SQL. there are two tables
**GroupRecords**
Id (int, primary key)
Name (nvarchar)
SchoolYear (datetime)
RecordDate (datetime)
IsUpdate (bit)
**People**
Id (int, primary key)
GroupRecordsId (int, foreign key to GroupRecords.Id)
Name (nvarchar)
Bio (nvarchar)
Location (nvarchar)
return a distinct list of people who belong to GroupRecords that have a SchoolYear of '2000'. In the returned list, people.name should be unique (no duplicate People.Name), in case of a duplication only the person who belong to the GroupRecords with the later RecordDate should be returned.
It would probably be better to write a stored procedure for this right?
This is untested, but it should do what is required in the question.
It selects all details about the person.
The subquery will make it match only the latest RecordDate for a single name. It will also look only in the right GroupRecord because of the Match between the ids.
SELECT
People.Id,
People.GroupRecordsId,
People.Name,
People.Group,
People.Bio,
People.Location
FROM
People
INNER JOIN GroupRecords ON GroupRecords.Id = People.GroupRecordsId
WHERE
GroupRecords.SchoolYear = '2000/1/1' AND
GroupRecords.RecordDate = (
SELECT
MAX(GR2.RecordDate)
FROM
People AS P2
INNER JOIN GroupRecords AS GR2 ON P2.GroupRecordsId = GR2.Id
WHERE
P2.Name = People.Name AND
GR2.Id = GroupRecords.Id
)
Select Distinct ID
From People
Where GroupRecordsID In
(Select Id From GroupRecords
Where SchoolYear = '2000/1/1')
This will produce a distinct list of those individuals in the 2000 class...
but I don't understand what you're getting at with the cpmment about duplicates... please elaborate...
It reads as though you're talking about when two different people happen to have the same name you don't want them both listed... Is that really what you want?
MySQL specific:
SELECT *
FROM `People`
LEFT JOIN `GroupRecords` ON `GroupRecordsId` = `GroupRecords`.`Id`
GROUP BY `People`.`Name`
ORDER BY `GroupRecords`.`RecordDate` DESC
WHERE `GroupRecords`.`SchoolYear` = '2000/1/1'
people.name should be unique (no duplicate People.Name)
? Surely you mean no duplicate People.ID?
in case of a duplication only the person who belong to the GroupRecords with the later RecordDate should be returned.
There's the rub — that's the bit that it's not obvious how to do in plain SQL. There are a number of approaches to the “For each X, select the row Y with maximum/minimum Z” question; which work and which perform better depend on which database software you're using.
http://kristiannielsen.livejournal.com/6745.html has some good discussion of some of the usual techniques for attacking this (in the context of MySQL, but widely applicable).