How to count and join between two MySQL tables? - mysql

I want to write out the number of times a car has been rented and I just cant get it to work, I have two tables. one is called vehicle and the other rental.
In rental is where all the "rentings" go when you book a car and all the vehicles is stored in vehicle. This is the query I made that almost works.
SELECT vehicle.id,COUNT(rental.vid) as rented,IFNULL(rental.vid,0) as nothing, vehicle.make as make, vehicle.model as model, vehicle.regnr as regnr, vehicle.color as color, vehicle.state as state, vehicle.imgurl as img, vehicle.description as description, vehicle.id
FROM rental,vehicle
WHERE vid = vehicle.id GROUP BY vid
and will print out this:
The rest which doesn't have a value (never been rented) isn't there, I have tried a lot of different ways with IFNULL but haven't gotten anywhere.

Select from Vehicle table and Left Join to Rental table. This will include Vehicle that have never been Rented and their Count(rental.vid) will be 0:
SELECT vehicle.id
,COUNT(rental.vid) as rented
, vehicle.make as make
, vehicle.model as model
, vehicle.regnr as regnr
, vehicle.color as color
, vehicle.state as state
, vehicle.imgurl as img
, vehicle.description as description
FROM vehicle
left join rental on vid = vehicle.id
GROUP BY vehicle.id
Here is a simplified example
The implicit join you have in your example is equivalent to an inner join. With a left join you select all rows you want from your source table. If there are matches to the table you are left joining to, they will appear as well. It's a good way to append data to your source table.

Related

Join all link table entries in one single row

I've been trying to get a query which would allow me to put all music genres of an event (Link table) in a single row but I have been quite unsuccessful so far; it constantly returns 2 rows with the same information about the event in each but changing the music genre entries at the LEFT JOIN. Here's my query:
SELECT
events.*
, music_genres_link.*
FROM events
LEFT JOIN music_genres_link
ON events.id = music_genres_link.event_id
WHERE events.id=1
ORDER BY date DESC
And here's what it returns:
How do I get these two rows together in a single one? I need both the genre_title and genre_id columns.
I'd like to get the whole event row and left join all the music genres found on the link table to the left of the result, as such:
[event result] [music_genre_1 (id, title)] [music_genre_2 (id, title)] etc
I suspect you just want group_concat():
SELECT e.*, GROUP_CONCAT(mgl.genre_title) as genres
FROM events e LEFT JOIN
music_genres_link mgl
ON e.id = mgl.event_id
WHERE e.id = 1
GROUP BY e.id;
This assumes that you want the genre_title only. If you want the genre_id, then you can add another column.
It seems that you have 2 rows that match the join in music_genres_link. You can see that from the two 'gender_id' values - 5 and 295.
Ok now that you have edited your question, you want something that is not typical for SQL. You can achieve that with PIVOT but you dont have limit for the amount of genres and i wouldn't recommend it. You need to rethink your tables and what you want to achieve.

How to join on a row with max value

I have three tables: households, voters, door_knocks
Each household can have several voters associated with it. Each household can also have several door knocks associated with it.
I'm trying to pull together all the voters in a household and the date of the last door_knock from the door_knocks table and I'm having trouble figuring out the proper query syntax. Here is my latest attempt:
SELECT households.hh_id, voters.id
FROM households
INNER JOIN voters ON households.hh_id = voters.hh_id
INNER JOIN ( SELECT MAX(dk.date), dk.hh_id FROM door_knocks dk GROUP BY dk.date) dks
ON dks.hh_id = households.hh_id
WHERE households.street = ?
The above query pulls up one result for each door knock, however. I just want the the date from the last door knock.
So, what it sounds like you're hoping for conceptually is a table that lists the last date of a knock for each houshold.
You'd like to join against that table and combine it with the voters and the households.
what your query does is give you a table of all the dates (group by dk.date) and for each date list all the households.
If you group by hh_id instead, then you will get the max date for each given household.
SELECT households.hh_id, voters.id, dks.max_date
FROM households
INNER JOIN voters ON households.hh_id = voters.hh_id
INNER JOIN ( SELECT MAX(dk.date) as max_date, dk.hh_id FROM door_knocks dk GROUP BY dk.hh_id dks
ON dks.hh_id = households.hh_id
WHERE households.street = ?

SQL querying multiple tables for information

I have a little dilemma in joining data from 4 tables in one SQL query, I am using MySQL for the DB part and would appriciate any help you can give me.
Here is the task...
I have for tables with columns and data
Sale Items Owner Salesman
-------------- ----------- ----------- --------------
*Salesman_id Item_type *Owner_id *Salesman_id
*Owner_id Item_color Owner_name Salesman_name
Buyer_id *Owner_id
Price
I want to query these tables on the columns I have marked with emphases text. So I can get result like
Item type, Item color, Owner name, Salesman name, Salesman number.
I have gone through a countless number of iteration trying to achieve this both with JOIN and nested queries without sufficient result.
If there is a one-to-one relation you can use inner join
SELECT i.Item_type , i.Item_color ,o.Owner_name,sm.Salesman_name,sm.Salesman_id
FROM Salesman sm
INNER JOIN Sale s ON (s.Salesman_id = sm.Salesman_id )
INNER JOIN Owner o ON (s.Owner_id=o.Owner_id)
INNER JOIN Items i ON (i.Owner_id=o.Owner_id)
If there is one -to- many try with Left join
try this
SELECT Item_type, Item_color, Owner_name, Salesman_name, Sale.Salesman_id FROM Items
INNER JOIN Owner USING(Owner_id)
INNER JOIN Sale USING(Owner_id)
INNER JOIN Salesman ON Salesman.Salesman_id=Sale.Salesman_id
why doesn't the Items table have a primary key?
A solution when we're not joining, and you want it them to just display their values, you can do something like (I know this doesn't directly answer OP's question, but I'm getting there...)
SELECT sale.`salesman_id`,sale.`owner_id`,
items.`order_id`,
owner.`owner_id`,
salesman.`salesman_id`
FROM `Sale` sale,
`Items` items,
`Owner` owner,
`Salesman` salesman
And that should return everything.
However, your question states that we are joining. Could you put some data into something like SQLFiddle so I have some visual representation? and a brief summary of what you're trying to accomplish - as in where you want the joins?

I can't wrap my head around joins

So, alright, I have a few tables. My current query runs against a "historical" table. I want to do a join of some kind to get the most recent status from my Current table. These tables share a like column, called "ID"
Here's the structure
ddCurrent
-ID
-Location
-Status
-Time
ddHistorical
-CID (AI field to keep multiple records per site)
-ID
-Location
-Status
-Time
My goal now is to do a simple join to get all the variables from ddHistorical and the current Status from ddCurrent.
I know that they can be joined on ID since both of them have the same items in their ID tables, I just can't figure out which kind of join is appropriate or why?
I'm sure someone may provide a specific link that goes into great detail explaining, but I'll try to summarize it this way. When writing a query, I try to list the tables from the position of what table do I want to get data from and have that as my first table in the "FROM" clause. Then, do "JOIN" criteria to other tables based on relationships (such as IDs). In your example
FROM
ddHistorical ddH
INNER JOIN ddCurrent ddC
on ddH.ID = ddC.ID
In this case, INNER JOIN (same as JOIN) the ddHistorical table is the left table(listed first for my styling consistency and indentation) and ddCurrent is the right table. Notice my ON criteria that joins them together is also left alias.column = right alias table.column -- again, this is just for mental correlation purposes.
an Inner Join (or JOIN) means a record MUST have a match on each side, otherwise it is discarded.
A LEFT JOIN means give me all records in the LEFT table (ddHistorical in this case), regardless of a matching in the right-side table (ddCurrent). Not practical in this example.
A RIGHT JOIN is the reverse... give me all records from the RIGHT-side table REGARDLESS of a matching record in the left side table. Most of the time you will see LEFT-JOINs more frequently than RIGHT-JOINs.
Now, a sample to mentally get the left-join. You work at a car dealership and have a master table of 10 cars that are sold. For a given month, you want to know what IS NOT selling. So, start with the master table of all cars and look at the sales table for what DID sell. If there is NO such sales activity the right-side table will have NULL value
select
M.CarID,
M.CarModel
from
MasterCarsList M
LEFT JOIN CarSales CS
on M.CarID = CS.CarID
AND month( CS.DateSold ) = 4
where
CS.CarID IS NULL
So, my LEFT join is based on a matching car ID -- AND -- the month of sales activity is 4 (April) as I may not care about sales for Jan-Mar -- but would also qualify year too, but this is a simple sample.
If there is no record in the Car Sales table it will have a NULL value for all columns. I just happen to care about the car ID column since that was the join basis. That is why I am including that in the WHERE clause. For all other types of cars that DO have a sale it will have a value.
This is a common approach you will see in querying where someone looking for all regardless of other... Some use a where NOT EXIST ( subselect ), but those perform slower because they test on every record. Having joins is much faster.
Other examples may be you want a list of all employees of a company, and if they had some certification / training to show it... You still want all employees, but LEFT-JOINING to some certification/training table would expose those extra field as needed.
select
Emp.FullName,
Cert.DateCertified
FROM
Employees Emp
Left Join Certifications Cert
on Emp.EmpID = Cert.EmpID
Hopefully these samples help you understand better the relationship for queries, and now to actually provide answer for your needs.
If what you want is a list of all "Current" items and want to look at their historical past, I would use current FIRST. This might be if your current table of things is 50, but historically your table had 420 items. You don't care about the other 360 items, just those that are current and the history of those.
select
ddC.WhateverColumns,
ddH.WhateverHistoricalColumns
from
ddCurrent ddC
JOIN ddHistorical ddH
on ddC.ID = ddH.ID
If there is always a current field then a simple INNER JOIN will do it
SELECT a.CID, a.ID, a.Location, a.Status, a.Time, b.Status
FROM ddHistorical a
INNER JOIN ddCurrent b
ON a.ID = b.ID
An INNER JOIN will omit any ddHistorical rows that don't have a corresponding ID in ddCurrent.
A LEFT JOIN will include all ddHistorical rows, even if they don't have a corresponding ID in ddCurrent, but the ddCurrent values will be null (because they're unknown).
Also note that a LEFT JOIN is just a specific type of outer join. Don't bother with the others yet - 90% or more of what you'll ever do will be INNER or LEFT.
To include only those ddHistorical rows where the ID is in ddCurrent:
SELECT h.CID, h.ID, h.Location, h.Status, c.Status, h.Time
FROM ddHistorical h
INNER JOIN ddCurrent c ON h.ID = c.ID
If you want to include ddHistorical rows even if the ID isn't in ddCurrent:
SELECT h.CID, h.ID, h.Location, h.Status, c.Status, h.Time
FROM ddHistorical h
LEFT JOIN ddCurrent c ON h.ID = c.ID
If all ddHistorical rows happen to match an ID in ddCurrent, note that both queries will return the same result.

When to use a left outer join?

I don't understand the concept of a left outer join, a right outer join, or indeed why we need to use a join at all! The question I am struggling with and the table I am working from is here: Link
Question 3(b)
Construct a command in SQL to solve the following query, explaining why it had to employ the
(outer) join method. [5 Marks]
“Find the name of each staff member and his/her dependent spouse, if any”
Question 3(c) -
Construct a command in SQL to solve the following query, using (i) the join method, and (ii) the
subquery method. [10 Marks]
“Find the identity name of each staff member who has worked more than 20 hours on the
Computerization Project”
Can anyone please explain this to me simply?
Joins are used to combine two related tables together.
In your example, you can combine the Employee table and the Department table, like so:
SELECT FNAME, LNAME, DNAME
FROM
EMPLOYEE INNER JOIN DEPARTMENT ON EMPLOYEE.DNO=DEPARTMENT.DNUMBER
This would result in a recordset like:
FNAME LNAME DNAME
----- ----- -----
John Smith Research
John Doe Administration
I used an INNER JOIN above. INNER JOINs combine two tables so that only records with matches in both tables are displayed, and they are joined in this case, on the department number (field DNO in Employee, DNUMBER in Department table).
LEFT JOINs allow you to combine two tables when you have records in the first table but might not have records in the second table. For example, let's say you want a list of all the employees, plus any dependents:
SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_last, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE INNER JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN
The problem here is that if an employee doesn't have a dependent, then their record won't show up at all -- because there's no matching record in the DEPENDENT table.
So, you use a left join which keeps all the data on the "left" (i.e. the first table) and pulls in any matching data on the "right" (the second table):
SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_first, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE LEFT JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN
Now we get all of the employee records. If there is no matching dependent(s) for a given employee, the dependent_first and dependent_last fields will be null.
example (not using your example tables :-)
I have a car rental company.
Table car
id: integer primary key autoincrement
licence_plate: varchar
purchase_date: date
Table customer
id: integer primary key autoincrement
name: varchar
Table rental
id: integer primary key autoincrement
car_id: integer
bike_id: integer
customer_id: integer
rental_date: date
Simple right? I have 10 records for cars because I have 10 cars.
I've been running this business for 10 years, so I've got 1000 customers.
And I rent the cars about 20x per year per cars = 10 years x 10 cars x 20 = 2000 rentals.
If I store everything in one big table I've got 10x1000x2000 = 20 million records.
If I store it in 3 tables I've got 10+1000+2000 = 3010 records.
That's 3 orders of magnitude, so that's why I use 3 tables.
But because I use 3 tables (to save space and time) I have to use joins in order to get the data out again
(at least if I want names and licence plates instead of numbers).
Using inner joins
All rentals for customer 345?
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
WHERE customer.id = 345.
That's an INNER JOIN, because we only want to know about cars linked to rentals linked to customers that actually happened.
Notice that we also have a bike_id, linking to the bike table, which is pretty similar to the car table but different.
How would we get all bike + car rentals for customer 345.
We can try and do this
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
INNER JOIN bike on (bike.id = rental.bike_id)
WHERE customer.id = 345.
But that will give an empty set!!
This is because a rental can either be a bike_rental OR a car_rental, but not both at the same time.
And the non-working inner join query will only give results for all rentals where we rent out both a bike and a car in the same transaction.
We are trying to get and boolean OR relationship using a boolean AND join.
Using outer joins
In order to solve this we need an outer join.
Let's solve it with left join
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id) <<-- link always
LEFT JOIN car on (car.id = rental.car_id) <<-- link half of the time
LEFT JOIN bike on (bike.id = rental.bike_id) <<-- link (other) 0.5 of the time.
WHERE customer.id = 345.
Look at it this way. An inner join is an AND and a left join is a OR as in the following pseudocode:
if a=1 AND a=2 then {this is always false, no result}
if a=1 OR a=2 then {this might be true or not}
If you create the tables and run the query you can see the result.
on terminology
A left join is the same as a left outer join.
A join with no extra prefixes is an inner join
There's also a full outer join. In 25 years of programming I've never used that.
Why Left join
Well there's two tables involved. In the example we linked
customer to rental with an inner join, in an inner join both tables must link so there is no difference between the left:customer table and the right:rental table.
The next link was a left join between left:rental and right:car. On the left side all rows must link and the right side they don't have to. This is why it's a left join
You use outer joins when you need all of the results from one of the join tables, whether there is a matching row in the other table or not.
I think Question 3(b) is confusing because its entire premise wrong: you don't have to use an outer join to "solve the query" e.g. consider this (following the style of syntax in the exam paper is probably wise):
SELECT FNAME, LNAME, DEPENDENT_NAME
FROM EMPLOYEE, DEPENDENT
WHERE SSN = ESSN
AND RELATIONSHIP = 'SPOUSE'
UNION
SELECT FNAME, LNAME, NULL
FROM EMPLOYEE
EXCEPT
SELECT FNAME, LNAME, DEPENDENT_NAME
FROM EMPLOYEE, DEPENDENT
WHERE SSN = ESSN
AND RELATIONSHIP = 'SPOUSE'
In general:
JOIN joints two tables together.
Use INNER JOIN when you wanna "look up", like look up detailed information of any specific column.
Use OUTER JOIN when you wanna "demonstrate", like list all the info of the 2 tables.