This query used to work fine but the trainers table no longer contains a name field so obviously it doesn't work anymore. The trainers table does contain the person_id and the trainer is a person in the persons table. With some other mechanism (nested select, self join, ...) I need to get the person_id from the trainer table, and then get the trainers name from the persons table, and then return the information in the same format as the original query. Can this be done with one statement?
SELECT
entries.entry_id, entries.entry_no, dogs.name,
persons.name, trainers.name
FROM
entries
JOIN
dogs ON entries.dog_id = dogs.dog_id
JOIN
persons ON dogs.owner = persons.person_id
JOIN
trainers ON entries.trainer_id = trainers.trainer_id
WHERE
entries.show_id = 5
Yes, just do an extra join with persons. Also: get into the habit of using aliases for every table you join. It increases readibility and you have to type less.
SELECT e.entry_id, e.entry_no, d.name, p.name, tp.name
FROM entries e
JOIN dogs d ON e.dog_id = d.dog_id
JOIN persons p ON d.owner = p.person_id
JOIN trainers t ON e.trainer_id = t.trainer_id
JOIN persons tp ON tp.person_id = t.person_id
WHERE e.show_id = ?
remove trainers.name from the select field list
add JOIN person tname ON person.id = trainers.trainer_id
add tname.name to select field-list
that should do it (if I read your text correctly)
Related
I am working from two tables in a dataset. Let's call the first one 'Demographic_Info', the other 'Study_Info'. The two tables both have a Subject_ID column. How can I run a query that will return all of the Subject_IDs where Sex = Male (from Demographic_Info) but also where the Study Case = Case (from Study_Info)?
Is this an inner join? Do I need to make a combined table?
I just don't know what function to use. I know how to select for each of these conditions in each table individually, but not how to run them against eachother.
Yes, you will want to inner join and then use the where clause to filter on both tables.
select
s.Subject_ID
from `Study_info` s
inner join `Demographic_info` d on s.Subject_ID = d.Subject_ID
where d.Sex = 'Male'
and s.Study_Case = 'Case' -- Unclear from your question about the actual field name
The aliases s and d will be useful for organizing which table each field comes from (or if the same field occurs in both tables).
Similarly, you could filter first and then perform the join.
with study as (select * from `Study_info` where Study_Case = 'Case'),
demographics as (select * from `Demographic_info` where Sex = 'Male')
select s.Subject_ID
from study s
inner join demographics d on s.Subject_ID = d.Subject_ID
I have a main table M (Movies) and other tables L (Location), G (Genre), and S (Sub Genre). Each of the "other" tables are in a one to many relationship to table M, using.
I want to list all the Blu Ray titles and pull in their Location, Length (Time), Comments, Genre, and Sub Genre.
My query is:
SELECT L.Location, M.Title, M.Length, M.Comments, G.Genre, S.SubGenre
FROM ((L
INNER JOIN M ON M.Location = L.ID)
INNER JOIN G ON M.Genre = G.ID)
INNER JOIN SubGenre ON M.SubGenre = SubGenre.ID
ORDER BY M.ID
WHERE M.Type is "BluRay"
ORDER BY M.ID;
It gives me a subset of what the subset (26) of what the total number of records should be (447.)
1. Do I have the proper table relationships?
2. Do I really need the parentheses? (error without them)
3. How do I change my query to give me all the Location records, with the appropriate movie-related information?
4. What if I want to add additional tables?
The DB schema:
-- Note that Type and Length are in between square brackets, because those are reserved words.
-- Avoid use of reserved words with MovieType and MovieLength
SELECT
L.LocationName
, M.Title
, M.[Length]
, M.Comments
, G.GenreName
, S.SubGenreName
FROM Movies M
INNER JOIN Location L ON L.LocationID = M.LocationID
INNER JOIN Genre G ON G.GenreID = M.GenreID
INNER JOIN SubGenre S ON S.SubGenreID = M.SubGenreID
WHERE M.[Type] = 'BluRay'
ORDER BY M.MovieID
You need to JOIN on shared table columns.
For "How to change your query to give all Location records, with appropriate movie-related information" that depends on what you think is appropriate.
You should not need the parentheses. Unless you are using a SQL database I am not familiar with.
You do not need to put the INNER in because the default JOIN is INNER JOIN in all flavors of SQL databases. You also have 2 ORDER BY M.ID you only want the one after the WHERE.
I am not sure what you mean by more tables do you mean you tables to the JOIN or actually more tables?
I have 4 tables in sqlite3:
students(student_id, student_name)
instructors(instructor_id, instructor_name)
courses(course_id, course_name)
and
enrollments(enroll_id, student_id, instructor_id, course_id)
With the last 3 columns having a foreign key reference to the relevant columns in the first 3 tables
When I try to do a query that shows only the student’s name, instructor’s name and course name where an enroll_id is equal to 001 for example
SELECT students.student_name, instructors.instructor_name, courses.course_name
FROM users, instructors, courses INNER JOIN enrollments
WHERE enrollments.enroll_id = 001;
I'm getting a lot of data from all tables, but not a single tuple with just the relevant enroll data assigned to enroll_id 001. Any help is appreciated
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax. The right way to express this query is:
SELECT s.student_full_name, i.instructor_name, c.course_name
FROM enrollments e JOIN
instructors i
ON e.instructor_id = i.instructor_id JOIN
courses c
ON e.course_id = c.course_id JOIN
students s
ON e.student_id = s.student_id
WHERE e.enroll_id = 001;
The use of table aliases is highly recommended. It makes the query easier to write and to read.
Try this:
SELECT students.student_full_name, instructors.instructor_name, courses.course_name
FROM users, instructors, courses, enrollments
WHERE enrollments.enroll_id = 001
and enrollments.student_id = users.student_id
and enrollments.instructor_id = instructors.instructor_id
and enrollments.course_id = courses.course_id;
I have 2 tables:
Person table with column person_id
Employee table with columns emp_type = full or part
I need a query that returns everyone in Person, but exclude full time employees. What I'm struggling with is not all Persons are necessarily in Employee table.
Can someone help me out? Thanks!
You can try code below, but you didn't give us your tables structure so I can only guess what do you mean here.
select *
from person p
left join employee e on p.person_id = e.person_id
where p.emp_type <> 'full'
Since you didn't post your full query or table structure information, you'll need to make adjustments. But using a not exists clause is probably the most straight forward way of doing this.
select p.*
from person p
where not exists (select null
from employee e
where e.person_id = p.person_id
and e.emp_type = 'full')
In Postgres, is there a way to perform a left join between tables linked by a junction table, with some filtering on the linked table?
Say, I have two tables, humans and pets, and I want to perform a query where I have the human ID, and the pet name. If the human ID exists, but they don't have a pet with that name, I still want the human's row to be returned.
If I had a FK relationship from pets to humans, this would work:
select h.*, p.*
from humans as h
left join pets as p on p.human_id = h.id and p.name = 'fluffy'
where h.id = 13
and I'd get a row with human 13's details, and fluffy's values. In addition, if human 13 didn't have a pet named 'fluffy', I'd get a row with human 13's values, and empty values for the pet's columns.
BUT, I don't have a direct FK relationship, I have a junction table between humans and pets, so I'm trying a query like:
select h.*, p.*
from humans as h
left join humans_pets_junction as j on j.human_id = h.id
left join pets as p on j.pet_id = p.id and p.name = 'fluffy'
where h.id = 13
Which returns rows for all of human 13's pets, with empty columns except for fluffy's row.
If I add p.name = 'fluffy' to the WHERE clause, that filters out all the empty rows, but also means I get 0 rows if human 13 doesn't have a pet named fluffy at all.
Is there a way to replicate the behavior of the FK-style left join, but when used with a junction table?
One method is to do the comparison in the where clause:
select h.*, p.*
from humans as h left join
humans_pets_junction as j
on j.human_id = h.id left join
pets as p
on j.pet_id = p.id and p.name = 'fluffy'
where h.id = 13 and (p.name = 'fluffy' or p.id is null);
Alternatively, join the junction table and the pets table as a subquery or CTE:
select h.*, p.*
from humans h left join
(select j.*
from humans_pets_junction j join
pets p
on j.pet_id = p.id and p.name = 'fluffy'
) pj
on pj.human_id = h.id
where h.id = 13;
In Postgres you can use parentheses to prioritize JOIN order. You do not need a subquery:
SELECT h.*, p.id AS p_id, p.name AS pet_name
FROM humans h
LEFT JOIN (pets p
JOIN humans_pets_junction j ON p.name = 'fluffy'
AND j.pet_id = p.id
AND j.human_id = 13) ON TRUE
WHERE h.id = 13;
Per documentation:
Parentheses can be used around JOIN clauses to control the join order.
In the absence of parentheses, JOIN clauses nest left-to-right.
I added the predicate j.human_id = 13 to the join between your junction table and the pets to eliminate irrelevant rows at the earliest opportunity. The outer LEFT JOIN only needs the dummy condition ON TRUE.
SQL Fiddle.
Aside 1: I assume you are aware that you have a textbook implementation of a n:m (many-to-many) relationship?
How to implement a many-to-many relationship in PostgreSQL?
Aside 2: The unfortunate naming convention in the example makes it necessary to deal out column aliases. Don't use "id" and "name" as column names in your actual tables to avoid such conflicts. Use proper names like "pet_id", "human_id" etc.