Join tables and add column only with a specific value - sql

I have four tables (a, b, c, d) in PostgreSQL database:
I can connect these tables with subject.id and project.id unique keys. My query is:
SELECT subject_id, firstname, lastname, national_id, project_title, project_id, note_template
FROM project_subject
JOIN subject ON subject.id = project_subject.subject_id
JOIN project ON project.id = project_subject.project_id
JOIN subject_note ON subject_note.subject_id = project_subject.subject_id
WHERE project_id = xxxx
My problem is that in table d (subject_notes) one subject can have several notes (varchar) plus selectable note_template (int). I would like to have joined table with columns subject_id, firstname, lastname, national_id, project_title, project_id and note_template. When I join four tables I get result with several same subject rows with different notes. I would like to have table where each subject is listed only one time and to the last column value is added only when note_template=16. Rest of the subjects would have null value for note_template.

Change the last join to a LEFT join and add the condition note_template = 16 in the ON clause:
LEFT JOIN subject_note ON subject_note.subject_id = project_subject.subject_id
AND subject_note.note_template = 16

Related

Selecting two names based on ID stored in different table

Suppose I have two tables:
Table 1: tasks with columns (id, authorId, assigneeId)
Table 2: employee with columns (id, name)
authorId and assigneeId in Table 1 are referenced to the id column in Table 2.
What is the way to select Task ID, Author Name and Assignee Name (Assignee name defaults to 'null' if no assigneeId is present) from these two tables?
I am not sure how to start, thus making it difficult. Could anyone give a hint on how to start the code?
You can join twice:
select t.id, e1.name as author_name, e2.name as assignee_name
from tasks t
left join employees e1 on e1.id = t.author_id
left join employees e2 on e2.id = t.assignee_id

joining a table on 2 fields

I want to pull a person and their supervisor names from a table. The persons table has the supervisor_id and the person_id. The names table has name_id and a Full Name field. If I join Person ON either supervisor_id or person_id, how do I get the other to display as well?
You need to join twice, one for each relationship you have:
SELECT
-- Persons' columns
P.*,
-- Superviser name columns
SN.*,
-- Person name columns
PN.*
FROM
persons AS P
LEFT JOIN names AS SN ON P.supervisor_id = SN.name_id
LEFT JOIN names AS PN ON P.person_id = PN.name_id
Or you can join with an OR clause, but you won't be able to know which record did you join with unless you check with a CASE.
SELECT
-- Persons' columns
P.*,
-- name columns
N.*,
IsSupervisor = CASE WHEN P.supervisor_id = N.name_id THEN 'Yes' ELSE 'No' END
FROM
persons AS P
LEFT JOIN names AS N ON
P.supervisor_id = N.name_id OR
P.person_id = N.name_id
This last approach will display 2 rows as it will match either one or the other on different occasions, not both with the same persons row (as the first example).
A (self)join is what you need:
select p.*, supervisor=ps.name
from Person p join person ps on p.supervisor_id=ps.id

How to merge two tables with having same column name

select *
INTO [dbo].[aTable]
from dbo.bt btg left join dbo.btt bta on btg.specialty = bta.specialty
order by 1, 6
I am getting the following error:
Column names in each table must be unique. Column name 'Specialty' in table 'aTable' is specified more than once.
Columns for bt table:
Location
Specialty
Provider
Column for btt table:
Specialty
Topic
I am trying to get Location, Specialty, Provider, and (join all topics for the specialty).
The issue here is the "Select *", which will select all fields in your result set. Try specifying the specific fields that you want to insert.
For instance:
SELECT Location, btg.Specialty, Provider, Topic
INTO INTO [dbo].[aTable]
from dbo.bt btg left join dbo.btt bta on btg.specialty = bta.specialty
order by 1, 6
Alias name is all you need to mention to avoid conflict when you join two tables with same column names.
SELECT btg.Location, btg.Specialty, btg.Provider,btg.Topic
INTO INTO [dbo].[aTable]
from dbo.bt btg join dbo.btt bta on btg.specialty = bta.specialty
order by 1, 6
you can do something like this:
select btg.*, topic
INTO [dbo].[aTable]
from dbo.bt btg left join dbo.btt bta on btg.specialty = bta.specialty

Insert primary keys from two newly created tables in a relationship table

I have one table which contained 4 records (PersonName, CityName, CityState, CityCountry) in two different tables. One of the tables now has personID, personName and the other one has Cityid, CityName, CityState, CityCountry.
Now I created third table which hold PersonId, CityId. How can I populate that table with the ids of person and city from the original table since they are split now. I want to get the ids from the newly created tables based on the relationship they had in the original table.
Can you not just join back to the original table?
INSERT PersonCity (PersonID, CityID)
SELECT p.PersonID, c.CityID
FROM OriginalTable o
INNER JOIN Person p
ON p.PersonName = o.Personname
INNER JOIN City c
ON c.CityName = o.CityName
AND c.CityState = o.CityState
AND c.CityCountry = o.CityCountry;

SQL Multiple Duplicate Row Detection

I'm trying to determine a correct way to isolate rows within a table that have the same values in 2 columns.
There are two tables, one (Name) with the person's names and IDs, and the other one (Nation) with people's IDs and their nations. I join the two tables with inner join, and now the new table columns consist of an ID, first name, last name, and nation. If I want to find pairs of people who have the same last name and are from the same nation, why isn't
select ID, FName, LName, Nation
from (Name inner join Nation on Name.ID = Nation.ID)
group by Name, Nation
having count(Name) > 1 and count(Nation) > 1
working?
I'm aiming for the result to be a table with columns:
ID -------First--------------- Last ---------Nation
where the last names and nations will be identical pairs while first names will be different.
I feel like the group by part isnt appropriate, but is there even an alternate way? Thanks for any help.
If you are using MS SQL Server:
select
*
from
(
select
Name.*,
Nation.Nation,
cnt = count(*) over(partition by LName, Nation)
from Name
join Nation on Nation.ID = Name.ID
) t
where cnt > 1
Try this:
SELECT * FROM (
SELECT Name.ID, Name.FName, Name.LName, Nation.Nation
FROM Name
INNER JOIN Nation ON (Name.ID = Nation.ID)
) a
INNER JOIN (
SELECT Name.ID, Name.FName, Name.LName, Nation.Nation
FROM Name
INNER JOIN Nation ON (Name.ID = Nation.ID)
) b ON (a.LName = b.LName AND a.Nation = b.Nation)
WHERE a.ID < b.ID
As Simon Righarts hinted, something's not right with the design.
Scenario 1)
If a name can have multiple nations, you would have 3 tables implementing an n:m relationship.
CREATE TABLE name (name_id int, name text, ...);
CREATE TABLE nation (nation_id int, nation text, ...);
CREATE TABLE nationality (name_id int references name(name_id)
,nation_id int references nation(nation_id)
... );
Query for the scenario:
SELECT a.name_id, a.fname, a.lname, n.nation
FROM name a
JOIN nationality na USING (name_id)
JOIN nation n USING (nation_id)
JOIN (
SELECT a.lname, na.nation_id
FROM name a
JOIN nationality na USING (name_id)
GROUP BY 1,2
HAVING count(*) > 1) x USING (lname, nation_id)
Scenario 2)
If a name can only have one nation, there would be a column nation_id in the table name:
CREATE TABLE name (name_id int
,name text
,nation_id int references nation(nation_id), ...);
CREATE TABLE nation (nation_id int, nation text, ...);
Query for this scenario:
SELECT a.name_id, a.fname, a.lname, n.nation
FROM name a
JOIN nation n USING (nation_id)
JOIN (
SELECT a.lname, a.nation_id
FROM name a
GROUP BY 1,2
HAVING count(*) > 1) x USING (lname, nation_id);
All multiple occurrences are included here, not just "pairs" - assuming you meant that.
Your actual description doesn't fit either scenario.