My doubt raises after i did this:
select name
from Highschooler
where ID in(select Friend.ID2
from Highschooler left join Friend
on Friend.ID1 = '1911' or Friend.ID1 = '1689');
The tables can be found here
The expected result was correct, and respects this clause:
Find the names of all students who are friends with someone named Gabriel.
Notice that i did not make any reference to the table Highschooler.ID
This seemed intuitive to me but then it got me thinking as Highschooler table does not have ID selected as primary key in my workbench.
So, when doing a left join, how does mysql know that i want to pair ID from highschooler with a column from Friend? The tables don't have any column name in common. So for all i know sql could try to pair grade from Highschooler, with ID1 from Friend.
The answer is that MySQL does not know how to join tables. You have to tell MySQL how to join the tables. In case of an outer join, use the on clause. However, in this particular case you do not need an outer join, since you want ids from the friend table.
Related
I've tried searching an answer for this and I can't realy find the one that fits what I'm looking for.
I'm making a small web application that allows an admin to create course material and a test, that a user will be assigned.
What I am trying to figure out, is how a user, who has been assigned a course, can access that course by clicking a button.
I have created one table which stores the user information, with a user ID being a primary key. I have a course table, which stores all materials and the course's test, with a course id being that table's primary key.
I made a third table which is an assigned_courses table, it contains two foreign keys. One referencing the user id from the user table, and one referencing the course id on the course table.
I've inserted a few images to show what you mean.
I can't quite figure out the Sql syntax to pull course materials and test based on the assigned_course table.
All feedback appreciated. This is the two foreign keys that reference the user id (id) and the course id(u_id)
Not sure what column names you have so I used * instead. You can use JOIN (AKA INNER JOIN) to link the tables together. You join on the primary keys of the 2 tables.
I have created one table which stores the user information, with a
user ID being a primary key. I have a course table, which stores all
materials and the course's test, with a course id being that table's
primary key.
I used id for your user table and course_id for the course table. Change as needed.
Find all courses for a given user.
SELECT a.*
FROM course a
JOIN assigned_course b ON a.course_id = b.id
WHERE b.u_id = :userId
;
Find all users for a given course.
SELECT a.*
FROM user a
JOIN assigned_course b ON a.id = b.u_id
WHERE b.id = :courseId
;
EDIT #1 - Subquery without JOIN
Thanks for your feedback, as I stated above, I was hoping to avoid a
join.
I highly recommend you learn joins. They are essential when you need to query more than 1 table. In this case, you can use a sub-query to find matching courses for a user but you won't be able to access that user data at the same time; that is the power of a join. I'll include a final example underneath showing how to get courses and user data at the same time.
Find all courses for a given user (using sub-query)
SELECT a.*
FROM course a
WHERE course_id IN (
SELECT id
FROM assigned_course b
WHERE u_id = :userId)
;
Final example showing courses related to users (many-to-many)
SELECT * -- You now have access to a, b, and c data
FROM course a
JOIN assigned_course b ON a.course_id = b.id -- joined by PKs
JOIN user c ON c.id = b.u_id -- joined by PKs
WHERE c.id = :userId
;
It sounds to me like you want to use SQL Join syntax which goes as follows:
select column1, column2, column3 etc...
from table1
join course on table1.id = course.id
join assigned_course on table1.id = assigned_course.id
replace the column1,2,3 etc with the actual column names, and replace the foreign_key_name with the actual name of the foreign key in the sub-table and the same for the user_primary_key
you can find some other examples of mysql joins here
as far as how to implement them into your html or php file, that is a very different question and would require knowing alot more about how your code is setup in the form
a place that is pretty user friendly is that might help with pulling the data is here just make sure you are aware of using prepared statements for your code
So my problem is as follow, I have a table in MySQL with a UserId column and an ObjectId column (its a many to many relationship), and what I would like is to have is a query that gives me the list of objects that user X and Y share. Not sure how to make the joins to make this happen.
Use query something like below using self join
Select columns from table t1 join table t2 on t1.objectid=t2.objectid where t1.userid=X and t2.userid=Y
The specific problem is listing the names of the teachers that never graded.
I have 'teachers' table with the columns 'Name' and 'ID'.
And 'grades' table with the column 'IDTeacher' and 'Grade'.
Don't get why this doesn't work:
Select Name from teachers where not exists(Select * from grades, teachers)
You can just join it with the grades table and use the ones where the join returns "null" for the right side:
SELECT
name
from
teachers t
LEFT JOIN
grades g
on
t.teacher = g.teacher
WHERE
ISNULL(g.teacher)
edit: Thought about a right join instead, but no, the right join might not work, if the teacher has no entry in the grades table. (Then you would miss him completely, even if he is in the teacher table)
You could also use WHERE IN for this:
SELECT
name
FROM
teachers
WHERE
name
NOT IN (SELECT name from grades)
BUT the MySQL Optimizer will rewrite this to exactly the correlated subquery #Gordon Linoff has written. Using WHERE NOT IN is just easier to read imho.
Your query does work, it just doesn't do what you think it should. The subquery creates a cartesian product between the two tables. If both tables have rows, then the cartesian product has rows and the where clause will always be true.
You can take this approach, but you need a correlated subquery:
Select Name
from teachers t
where not exists (Select 1 from grades g where g.idteacherid = t.id);
Note that this query only has one table in the subquery.
There are other ways to write this query, but this seems to be the approach you are heading in. And, not exists is a very reasonable approach.
I have three tables that I want to combine.
I have the following query to run:
DROP TABLE
IF EXISTS testgiver.smart_curmonth_downs;
CREATE TABLE testgiver.smart_curmonth_downs
SELECT
ldap_karen.uid,
ldap_karen.supemail,
ldap_karen.regionname,
smart_curmonth_downs_raw.username,
smart_curmonth_downs_raw.email,
smart_curmonth_downs_raw.publisher,
smart_curmonth_downs_raw.itemtitle,
smart_items.`Owner`
FROM
smart_curmonth_downs_raw
INNER JOIN ldap_karen ON smart_curmonth_downs_raw.username = ldap_karen.uid
INNER JOIN smart_items ON smart_curmonth_downs_raw.itemtitle = smart_items.Title
I want to know how to create the joins while maintaining a one to one relationship at all times with rows in table smart_curmonth_downs_raw.
For instance if there is not a uid in ldap_karen I have issues. And then the last issue I have found is that our CMS is allowing for duplicate itemtitle. So if I run my query I am getting a lot more rows because it is creating a row for each itemtitle. For example would there be a way to only catch the last itemtitle that is in smart_items. I would just really like to maintain the same number of rows - and I have no control over the integrity issues of the other tables.
The smart_curmonth_downs_raw table is the raw download information (download stats), the karen table adds unique user information, and the smart_items table adds unique items (download) info. They are all important. If a user made a download but is knocked off the karen table I would like to see NULLs for the user info and if there is more than one item in smart_items that has the same name then I would like to see just the item with the highest ID.
It sounds like relationship between smart_curmonth_downs_raw and ldap_karen is optional, which means you want to use a LEFT JOIN which all the rows in the first table, and, if the right table does not exists, use NULL as the right table's column values.
In terms of the last item in the smart_items table, you could use this query.
SELECT title, MAX(id) AS max_id
FROM smart_items
GROUP BY title;
Combining that query with the other logic, try this query as a solution.
SELECT COALESCE(ldap_karen.uid, 'Unknown') AS uid,
COALESCE(ldap_karen.supemail, 'Unknown') AS supemail,
COALESCE(ldap_karen.regionname, 'Unknown') AS regionname,
smart_curmonth_downs_raw.username,
smart_curmonth_downs_raw.email,
smart_curmonth_downs_raw.publisher,
smart_curmonth_downs_raw.itemtitle,
smart_items.`Owner`
FROM smart_curmonth_downs_raw
INNER JOIN (SELECT title, MAX(id) AS max_id
FROM smart_items
GROUP BY title) AS most_recent
ON smart_curmonth_downs_raw.itemtitle = most_recent.Title;
INNER JOIN smart_items
ON most_recent.max_id = smart_items.id
LEFT JOIN ldap_karen
ON smart_curmonth_downs_raw.username = ldap_karen.uid;
Please explain to me joins in simple language. Please do not post a web link as I need to read how a developer understand it, not an author.
Best I can point you to is A Visual Explanation of SQL Joins.
The diagrams helped me a lot.
Adding the main diagrams from the linked post here.
Inner Join
Inner join produces only the set of records that match in both Table A and Table B.
Full outer join
Full outer join produces the set of all records in Table A and Table B, with matching records from both sides where available. If there is no match, the missing side will contain null.
Left outer join
Left outer join produces a complete set of records from Table A, with the matching records (where available) in Table B. If there is no match, the right side will contain null.
Given Table Person And Information
SELECT *
FROM Person INNER JOIN
Information ON Person.ID = Information.ID
Will only return rows from both tables where both tables have the same IDs. So only if the ID exists in both Person and Information will the row be returned.
SELECT *
FROM Person LEFT JOIN
Information ON Person.ID = Information.ID
Will return all rows from Person, and only those that match from Information, where it does not match, it will return NULLs
SELECT *
FROM Person LEFT JOIN
Information ON Person.ID = Information.ID
WHERE Information.ID IS NULL
Will return all rows from Person that DOES NOT HAVE an entry in Information. This shows you the list of persons that do not have their Informaton updated yet.
I'm interpreting your question to mean joins in a very general sense, not each type of join, so if this is off the mark then I apologize:
Basically, joins enable you to get data from multiple tables in a single query by adding columns to your result set. So if you had the following tables:
Books (ID, Title, AuthorID)
Authors (ID, Name)
You could get a result set that looked like this:
Book | Author
'The Sirens of Titan' | 'Kurt Vonnegut'
'The Old Man and the Sea' | 'Earnest Hemingway'
By joining the two tables together like so:
select Books.Title as Book, Authors.Name as Author
from Books
inner join Authors on Authors.ID = Books.AuthorID
An inner join is the simplest type of join; it may be difficult to understand the point of outer joins without first having a strong grasp of inner joins and their uses.