MYSQL Join - Using join to get field through 4 tables - mysql

I have 4 tables and I wish to use a mysql inner join to the users name (table 1) and type of fav(table 4). Inorder to do this, I need to use user_id to get get corresponding fav_id on table 2, then use the fav_id to get type_of_fav_id on table 3, and finally use type_of_fav_id on table 3 to get type_of_fav on table 4. I will appreciate any help.
Table 1
Users
----------
user_id
first_name
last_name
Table 2
user_favorite
--------
user_fav_id
user_id
fav_id
Table 3
favorites
--------
fav_id
type_of_fav_id
Table 4
types_of_fav
--------
type_of_fav_id
type_of_fav

It's pretty straightforward, actually. Just join each of the four tables, linking the primary key of each to its foreign key counterpart in the following table. Then you can reference the fields that you want in your SELECT clause.
SELECT u.first_name, u.last_name, tof.type_of_fav
FROM users u
JOIN user_favorite uf ON u.user_id = uf.user_id
JOIN favorites f ON uf.fav_id = f.fav_id
JOIN types_of_fav tof on f.type_of_fav_id = tof.type_of_fav_id
It's a good idea to set up abbreviations of the table names as I have it here. You don't have to do that, but it's more concise and easier to work with. If you don't do it, you have to reference the full table name, to avoid ambiguity in field references: JOIN user_favorite on users.user_id = user_favorite.user_id, for example. That gets pretty long-winded.
If you don't include the tables when referencing the fields, the parser doesn't know which field you're referencing, since your field names aren't unique in your entire schema. So, you'll get an ambiguous field reference error.

Related

SQL Query Including Joins

So I have a database with two tables, profile, and friends. The primary key in profile is an auto incremented int, and it is a foreign key in friends. The fields in the profile table are: id, name, age, bio, motto, email_address.
The fields in friends is: initiator_id, receiver_id, date_added.
So ultimately I am trying to make a query where I set the initiator_id and get a list of receiver_id's, and use those id numbers to get them from the profile table.
I've tried left join's, inner joins, and joins in general. Open to suggestions, and interpretations on what these types of joins are actually doing.
select friends.receiver_id, profile.name
from profile
inner join friends on friends.initiator_id=1;
I need the fields to return the receiver_id number as well as the corresponding name for that id number.
The specification is a bit unclear. Sample data and expected output would go a longs ways towards illustrating the requirements.
But my guess (and without a specification, its just a guess) is that we are after the resultset returned from this query:
SELECT f.receiver_id
, p.name
FROM friends f
JOIN profile p
ON p.id = f.receiver_id
WHERE f.initiator_id = 1

How to get count by combining more than 2 tables in mysql

i have a table 'A' with status column, it can have 4 values. In table A i have table 'B's id, table B have table 'C's id. I want to get the status count FROM table 'A' by joining all these columns. The status column in table A is a foreign key from table 'D'. Table 'D' having status like 1-agreed, 2-not agreed etc
The question is missing some information that might be helpful. Particularly, what exactly you are wanting to count. (i.e. are you just trying to count ALL rows, or are you trying to count the number of rows in table A that have each status). I'll put together an answer that assumes that latter.
I'll also just assume that "id" is the primary key of its own table, and that id will be the id from other tables inside a table.
select A.statusField, count(*)
from A
join B on (A.Bid = B.id)
join C on (B.Cid = C.id)
group by A.statusField
Hope that helps.

MySQL queries on multiple tables

I know all about joining tables, but I'm having trouble figuring out what to do in this case.
I have a table users which contains a column called user_id which is an integer.
I have a second table called "follows" which contains a column "user_id" and a column called "follow_id". This table is used to log which other users each user follows (think Twitter).
I have a third table called posts which contains a column called user_id , which is a foreign key.
Ideally I'd like a single query that looks up the follows table, gets all the follow_ids from for a single user, then returns all posts from the posts table.
I suggest you to use LEFT JOIN
SELECT
follows.follow_id,
posts.*
FROM
follows
LEFT JOIN
post ON posts.user_id = follows.user_id
WHERE
follows.user_id = <UserID>

Select rows from a table not matched in another table

So I have the following:
A lookup table that has two columns and looks like this for example:
userid moduleid
4 4
I also have a users table that has a primary key userid which the lookup table references. The user table has a few users lets say, and looks like this:
userid
1
2
3
4
In this example, it show that the user with ID 4 has a match with module ID 4. The others are not matched to any moduleid.
I need a query that gets me data from the users table WHERE the moduleid is not 4. In my application, I know the module but I don't know the user. So the query should return the other userids apart from 4, because 4 is already matched with module ID 4.
Is this possible to do?
I think I understand your question correctly. You can use a sub-query to cross-check the data between both tables using the NOT IN() function.
The following will select all userid records from the user_tbl table that do not exist in the lookup_tbl table:
SELECT `userid`
FROM `user_tbl`
WHERE `userid` NOT IN (
SELECT DISTINCT(`userid`) FROM `lookup_tbl` WHERE moduleid = 4
)
There are several ways to do this, one pretty intuitive way (in my opinion) is the use an in predicate to exclude the users with moduleid 4 in the lookup table:
SELECT * FROM Users WHERE UserID NOT IN (SELECT UserID FROM Lookup WHERE ModuleID = 4)
There are other ways, with possibly better performance (using a correlated not exists query or a join for instance).
One other option is to use a LEFT JOIN so that you can get the values from both tables, even when there is not a match. Then, pick the rows where there is no userid value from the lookup table.
SELECT u.userid
FROM usersTable u
LEFT JOIN lookupTable lt ON u.userid = lt.userid
WHERE lt.userid IS NULL
Are you looking for a query like this?
select userid from yourtablename where moduleid<>4

Should I relate all of my MySQL tables to each other?

I'm working on a personal project for timekeeping on various projects, but I'm not sure of the best way to structure my database.
A simplified breakdown of the structure is as follows:
Each client can have multiple reports.
Each report can have multiple line items.
Each line item can have multiple time records.
There will ultimately be more relationships, but that's the basis of the application. As you can see, each item is related to the item beneath it in a one-to-many relationship.
My question is, should I relate each table to each "parent" table above it? Something like this:
clients
id
reports
id
client_id
line_items
id
report_id
client_id
time_records
id
report_id
line_item_id
client_id
And as it cascaded down, there would be more and more foreign keys added to each new table.
My initial reaction is that this is not the correct way to do it, but I would love to get some second(and third!) opinions.
The advantage of the way you're doing it is that you could check all time records for, say, a specific client id without needing a join. But really, it isn't necessary. All you need is to store a reference back up one "level" so to speak. Here are some examples from the "client" perspective:
To get a specific client's reports: (simple; same as current schema you suggest)
SELECT * FROM `reports`
WHERE `client_id` = ?;
To get a specific client's line items: (new schema; don't need "client_id" in table)
SELECT `line_items`.* FROM `line_items`
JOIN `reports` ON `reports`.`id` = `line_items`.`id`
JOIN `clients` ON `clients`.`id` = `reports`.`client_id`
WHERE `clients`.`id` = ?;
To get a specific client's time entries: (new schema; don't need "client_id" or "report_id" in table)
SELECT `time_records`.* FROM `time_records`
JOIN `line_items` ON `line_items`.`id` = `time_records`.`line_item_id`
JOIN `reports` ON `reports`.`id` = `line_items`.`id`
JOIN `clients` ON `clients`.`id` = `reports`.`client_id`
WHERE `client_id` = ?;
So, the revised schema would be:
clients
id
reports
id
client_id
line_items
id
report_id
time_records
id
line_item_id
EDIT:
Additionally, I would consider using views to simplify the queries (I assume you'll use them often), definitely creating indexes on the join columns, and utilizing foreign key references for normalization (InnoDB only).
No, if there is no direct relation in the elements of the model, then there should not be direct relation in the corresponding tables. Otherwise your data will have redundancies and you will have problems for updating.
This is the right way:
clients
id
reports
id
client_id
line_items
id
report_id
time_records
id
line_id
You don't need to create client_id on line_items table if you never join line items directly clients, becouse you can get that by reports table. Same happens to others FKs.
I recommend you think in your report needs/queries over this collection of data before create redundant foreign keys who can complicate your development.
Create redundant FKs is not difficult if you need them in the future, some ALTERS and UPDATE SELECTS solves your problem.
If you not have so much information in the line_items, you can denormalize and add this info in the time_records.
Anywhere there is a direct relationship between two tables, you should use foreign keys to keep the data integrity. Personally, I would look at a structure like this:
Client
ClientId
Report
ReportId
ClientId
LineItem
LineItemId
ReportId
TimeRecord
TimeRecordId
LineItemId
In this example, you do not need ClientId in LineItem because you have that relationship through the Report table. The major disadvantage of having ClientId in all of your tables is that if the business logic does not enforce consistency of these values (a bug is in the code) you can run into situations where you get different values if you search based on
Report:
ReportId = 3
ClientId = 2
LineItem:
LineItemId = 1
ReportId = 3
ClientId = 3
In the above situation, you would be looking at ClientId = 2 if your query went through Report and ClientId = 3 if your query went through LineItem It is difficult once this happens to determine which relationship is correct, and where the bug is.
Also, I would advocate for not having id columns, but instead more explicit names to describe what the id is used for. (ReportId or ClientId) In my opinion, this makes Joins easier to read. As an example:
SELECT COUNT(1) AS NumberOfLineItems
FROM Client AS c
INNER JOIN Report AS r ON c.ClientId = r.ClientId
INNER JOIN LineItem AS li ON r.ReportId = li.ReportId
WHERE c.ClientId = 12
As personal opinion, I would have:
clients
id
time_records
id
client_id
report
line_item
report_id
That way all of your fields are over in the time_records table. You can then do something like:
SELECT *
FROM 'time_records'
WHERE 'time_records'.'client_id' = 16542
AND 'time_records'.'report' = 164652
ORDER BY 'time_records'.'id' ASC