Multi/level query in MySQl - is an extra foreign key necessary? - mysql

Lets say that I have 3 tables:
departments, each of which has 0..n
jobs, each of which has 0..n
people
Given a department, how do I get all the people who work in that department? Can I do it with a single SELECT?
I have set up a fiddle with some sample data, but I can't formulate the correct query.
Can it be done with some JOIN magic? Or do I need to add a foreign key in the peeps table, pointing back to the department_id?

A simple join
SELECT people.*
FROM departments
INNER JOIN jobs ON departments.deperatment_id = jobs.deperatment_id
INNER JOIN people ON jobs.job_id = people.job_id
WHERE departments.deperatment_id = 1
You will need to amend the column names in the join conditions to the ones used in your tables.
Note that your sample tables on SQL fiddle do not have any indexes. Adding these is VERY important for performance.

Related

Selecting/Inserting data between 3 tables

I think there are something wrong with my structure. I have 3 tables in the database. I want to show all the supply in a specific division. I did some trial and errors but I can't insert another supply in the same plan id. I wanted to add more supplies in one of specific division / specific plan id.Here's my query to select the supplies.
SELECT
division.acronym,
supply.`name`,
supply.unit,
supply.supply_id,
supply.price,
supply.estimated_budget,
supply.quantity
FROM
division
INNER JOIN plan ON plan.plan_id = division.division_id
INNER JOIN supply ON supply.supply_id = plan.plan_id
The table is only available at documentation. So, I insert my ERD diagram as an image.
ERD edited
I think you should put division_id and supply_id to plan table as FOREIGN KEYS to join all three tables.
Then your query should look like:
division
INNER JOIN plan ON plan.division_id=division.division_id
INNER JOIN supply ON supply.supply_id=plan.supply_id

How To Write a Query That Is Based On Three Tables?

There are my tables. So basically I had to create a bunch of queries that were based off of two tables, which I did easily. The last question is asking to create a table that is based off of three tables, and the problem is I honestly cannot think of a way to reference all of these tables, it seems that there are not enough attributes in each table to reference three different ones.
Does anyone have any idea?
CRIME
crime_code PK
criminal_code FK
crime_desc
CRIMINAL
crim_code PK
jail_code FK
life_behind_bars
release_date
JAIL
jail_code PK
num_criminals_in_jail
cop_code FK
COP
cop_code
cop_Lname
cop_Fname
cop_phone
SELECT *
FROM CRIME c
INNER JOIN CRIMINAL cr ON c.criminal_code = cr.crim_code
INNER JOIN JAIL j ON cr.jail_code = j.jail_code
INNER JOIN COP cp ON j.cop_code = cp.cop_code
This is a simple select statement with multiple join. The first table CRIME joins to the second table CRIMINAL using the FK of CRIME to join to the PK of CRIMINAL, so on and so on.
Info on joins. http://www.w3schools.com/sql/sql_join.asp
This is all very basic stuff and can be found with a google search.

SQL - Joining tables BUT not always

I need to perform a query SELECT that joins three tables (no problem with that). Nonetheless, the third table can, or NOT, have any element that match the joining KEY.
I want ALL data from the first two tables and if the ITEMS have ALSO information in the third table, fetch this data to.
For example, imagine that the first table have a person, the second table have his/her address (everyone lives anywhere), the third table stores the driving license (not everyone has this) - but I need to fetch all data whether or not people (all people) have driving license.
Thanks a lot for reading, if possible to give you suggestion / solution!
Use LEFT JOIN to join the third table. Using INNER JOIN a row has to exists. Using LEFT JOIN, the 'gaps' will be filled with NULLs.
SELECT
p.PersonID, -- NOT NULL
-- dl.PersonID, -- Can be null. Don't use this one.
p.FirstName,
p.LastName,
a.City,
a.Street,
dl.ValidUntilDate
FROM
Person p
INNER JOIN Addresse a ON a.AddressID = p.HomeAddressID
LEFT JOIN DrivingLicence dl ON dl.PersonId = p.PersonID

Is this MySQL multiple table join OK?

I have one table service_contacts which can contain listids from the lists table and contactids from the contacts table. contact_list_relationship has the relationships between contacts and lists tables.
I'm trying to pull all the contacts which could be in a contactid in service_contacts, or in a listid (which each list contains contactids).
SELECT d.* FROM service_contacts a
LEFT JOIN lists b
ON a.calllistid=b.listid
LEFT JOIN contact_list_relationship c
ON c.listid=b.listid
INNER JOIN contacts d
ON d.contactid=c.contactid OR d.contactid=a.contactid
WHERE a.memberid=12345
This runs, and pulls the expected results. So far ... I'm just wondering if there might be a better way.
Assuming that the fields you are joining on are indexed / or preferably defined with FOREIGN KEY constraints (which enforce indexing) you should be fine.
However MySQL does not always use indexes even if they are available. To check the indexes are being used you can run an explain on your statement i.e.
EXPLAIN
SELECT d.* FROM service_contacts a
LEFT JOIN lists b
ON a.calllistid=b.listid
LEFT JOIN contact_list_relationship c
ON c.listid=b.listid
INNER JOIN contacts d
ON d.contactid=c.contactid OR d.contactid=a.contactid
WHERE a.memberid=12345;
the results will inform you which indexes are being used in the statement. If the results are not as expected you can force Mysql to use the indexes withby stating 'force key for join indexname after each reference to a table.

mysql table problem?

i have these two tables tables for a chatting app
users{user_id,username,pictures}
chat_data(con_id, chat_text}
i used this sql query
SELECT c.chat_text, u.username
FROM chat_data c, users u
WHERE c.con_id =1
but its giving me duplicate results, when i know thiers only row with the con_id =1, what is the problem with the query!! :))
You need to "join" the tables to avoid duplicates. For example
SELECT c.chat_text, u.username
FROM chat_data c, users u
WHERE c.con_id =1
and u.id = c.user_id
You can read a bit about relational algebra which is the theory behind relational databases.
The users and chat_data tables should be JOINED in order to get a unique tuple as result.
Since users and chat_data cannot be joined, you simply get Cartesian product of the two tables.
Cartesian Products
If two tables in a join query have no
join condition, then Oracle Database
returns their Cartesian product.
Oracle combines each row of one table
with each row of the other. A
Cartesian product always generates
many rows and is rarely useful. For
example, the Cartesian product of two
tables, each with 100 rows, has 10,000
rows. Always include a join condition
unless you specifically need a
Cartesian product. If a query joins
three or more tables and you do not
specify a join condition for a
specific pair, then the optimizer may
choose a join order that avoids
producing an intermediate Cartesian
product.
Refer: http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10759/queries006.htm
With a query like that, you will get as many rows in the results as there are rows in the table users.
It's because of the type of join the SQL is doing. Is it returning a row for each user you have? This is what I expect it is doing, i.e. if you have 2 users John and Jack then are you getting a row for both of these users being returned?
Are you just trying to get the data related to the users involved in a conversation? If so you need some link between the 2 tables, like foreign key references from the chat_data table referencing users.
As previously stated, you're missing a link between the two tables. If you are trying to retrieve the user associated to a particular chat you will need to add a foreign key reference in chat_data that references user.user_id. But if you are trying to get multiple users associated to a chat you would need to add a new table. Your new tables would look something like this:
users{user_id,username,pictures}
chat_data(con_id, chat_text}
user_chat(user_id, con_id) //By adding this new table you can have multiple users per chat
The the query would look something like
SELECT u.username, c.chat_text
FROM users u, chat_data c, user_chat uc
WHERE u.id = uc.id
AND c.con_id = uc.con_id