I'd like to make a self join which I did using LEFT JOIN but now I'd like to join 2 other tables and add a where on 2 of the fields of the joined table. The data table contains a self reference to its parent ID. I'd like to get the child name AND the parent name for a given CATEGORY and TYPE. I tried the following request:
SELECT d1.NAME as NAME, d1.Parent as Parent, d2.NAME as PARENT_NAME
FROM data as d1 LEFT OUTER JOIN data as d2 ON d1.PARENT = d2.ID
JOIN TYPE ON d1.T_ID
JOIN CATEGORY ON d1.CAT_ID
WHERE TYPE_NAME = 'Name'
AND CAT_NAME = 'Name'
But the result is the same with out without the "where" meaning that I get all the result for all CATEGORY and all the TYPE.
Your JOIN conditions are incomplete, so you are effectively getting a CROSS JOIN instead since wherever T_ID and CAT_ID are not 0 or NULL a JOIN will happen. Try changing them to (assuming the ID columns in the TYPE and CATEGORY tables are called ID):
JOIN TYPE ON d1.T_ID = TYPE.ID
JOIN CATEGORY ON d1.CAT_ID = CATEGORY.ID
Please correct your join condition at the time of joining
SELECT d1.NAME as NAME, d1.Parent as Parent, d2.NAME as PARENT_NAME
FROM data as d1
LEFT OUTER
JOIN data as d2 ON d1.PARENT = d2.ID
JOIN TYPE ON d1.T_ID **= someColumn**
JOIN CATEGORY ON d1.CAT_ID **= someColumn**
WHERE TYPE_NAME = 'Name'
AND CAT_NAME = 'Name'
Related
Below is something I am trying to achieve.
Data from 3 different files are loaded into a single table in which I need to categorize the data based on the names, and check for the best fit of the data across all rows.
The same name can have a maximum of 3 occurrences inside the table and a minimum of 1.
The data comparison should happen on all 3 rows or 2 rows (If the name did not come from one source) if there are more than one occurrences for a given name. If there is only 1 row for a given name that should be taken as the default value.
This is my attempt.
select
case
when (coalesce(length(A.x_manufacturer),0) > coalesce(length(B.x_manufacturer),0) AND coalesce(length(A.x_manufacturer),0) > coalesce(length(C.x_manufacturer),0)) then A.x_manufacturer
when (coalesce(length(B.x_manufacturer),0) > coalesce(length(A.x_manufacturer),0) AND coalesce(length(B.x_manufacturer),0) > coalesce(length(C.x_manufacturer),0)) then B.x_manufacturer
when (coalesce(length(C.x_manufacturer),0) > coalesce(length(A.x_manufacturer),0) AND coalesce(length(C.x_manufacturer),0) > coalesce(length(B.x_manufacturer),0)) then C.x_manufacturer
else C.x_manufacturer end as Best_Fit_x_manufacturer
from tbl1 A left outer join tbl1 B on
A.name = B.name
left outer join tbl1 C on C.name = B.name
where A.sourceid=1 and B.sourceid=2 and C.sourceid=3 group by
C.name
Sample Data in Table:
Name ManuFacturer source
A AB 1
A ABC 2
A ABCD 3
B BC 1
Expected Output
Name ManuFacturer source
A ABCD 3
B BC 1
As soon as you put a solid condition on an outer joined table, into the WHERE clause, the join reverts to INNER join behavior:
from
tbl1 A
left outer join tbl1 B on A.name = B.name
left outer join tbl1 C on C.name = B.name
where
A.sourceid=1 and
B.sourceid=2 and --wrong; this will cause A outer join B to become an INNER join
C.sourceid=3 --wrong; this will cause B outer join C to become an INNER join
Put your clauses in the ON instead:
from
tbl1 A
left outer join tbl1 B on A.name = B.name AND B.sourceid=2
left outer join tbl1 C on C.name = B.name AND C.sourceid=3
where
A.sourceid=1
The reason why is:
Outer joins generate NULLs in every column if there's no match between rows, hence B.sourceid might well be null in some rows of the result set. Specifying WHERE B.sourceid=2 causes all the rows where sourceid is null, to disappear, because 2 is not equal to null (nothing is equal to null). This means the only rows that you can possibly get out of it is rows where there IS a match.. Which is an inner join
Table 1 (Room Types)
type_id type_name
Table 2 (Rooms)
room_id room_type_id room_property_id
i want to get only those room types which are not included in the rooms table according to property_id
This is what i have done so far
SELECT `rt`.`type_id`,
`rt`.`type_name`
FROM `ae_room_type` AS `rt`
WHERE type_id NOT IN (
(SELECT GROUP_CONCAT(room_type_id)
FROM ae_rooms
WHERE room_properties_id = '5dea0ab1-e527-4882-a2df-9c592ea826a4'))
One simple approach is a LEFT JOIN:
SELECT t1.*
FROM room_types t1
LEFT JOIN rooms t2
ON t1.type_id = t2.room_type_id AND
t2.room_properties_id = '5dea0ab1-e527-4882-a2df-9c592ea826a4'
WHERE t2.room_type_id IS NULL;
The idea here is that we try to join each room type record to the rooms table. Those room types which never appear in the rooms table would have nothing to join to. In this case, such records would only appear once in the result set, not duplicated. A null value in the rooms table after the join is the marker for a room type which has not been used in any room.
You should also use a subquery to filter the desired room properties, and then use a LEFT JOIN with an IS NULL condition to get only the types not included in the remaining rooms:
SELECT rt.type_id,
rt.type_name
FROM ae_room_type as rt
LEFT JOIN (SELECT room_properties_id,
room_type_id
FROM ae_rooms
WHERE room_properties_id = '5dea0ab1-e527-4882-a2df-9c592ea826a4') AS r
ON rt.type_id = r.room_type_id
WHERE r.room_type_id IS NULL
I am trying to self join information from a table, to show a hierarchy (the table contains members, which consist of children and their parents). The table name is ‘members’, the four important columns are id, full_name, father_id and mother_id. The id's in the columns father_id and mother_id match the corresponding id's in column 'id'. As a result of the query, I would like to have a table with three columns, with column names 'Name', 'Father' and 'Mother'
I searched google, w3 schools and stack overflow, the closest to what I was looking for was a topic I found right here, called ‘Explanation of self-joins’ that had the following example code:
select
c1.Name , c2.Name As Boss
from
emp1 c1
inner join emp2 c2
on c1.Boss_id = c2.Id
I altered the query as follows (I didn't even dare include the third column yet :') ):
select
c1.full_name as Name, c2.full_name as Father
from
members1 c1
inner join members2 c2
on c1.father_id = c2.id
Unfortunately, I got an error message stating the following: 1146 - Table 'ppstb.members1' doesn't exist
I guessed it had something to do with how I simulated having two tables. The next thing I experimented with is:
select
c1.full_name , c2.full_name as Father
from
members c1, members c2
inner join members c2
on c1.father_id = c2.id
But this also gives an error: 1066 - Not unique table/alias: 'c2' What step am I missing?
last member should be c3 not c2
select
c1.full_name , c3.full_name as Father
from
members c1, members c2
inner join members c3
on c1.father_id = c3.id
I actually got the code working, using left-joins. I'm not sure why the inner joins wouldn't work, but this solved my problem:
SELECT
members.full_name, b.full_name AS Father, c.full_name AS Mother
FROM
members
LEFT JOIN
members b ON (members.father_id = b.id)
LEFT JOIN
members c ON (members.mother_id = c.id)
I have schema like this:
Now I would like to write query which returns me list of items with borrower name only if book is borrowed now, otherwise borrower name should be null.
I feel like it should be easy; I have been trying with just multple joins and NULL conditions but I still can't get what I want. Maybe should I change my schema?
SELECT items.*, borrowers.first_name, borrowers.last_name
FROM items
LEFT JOIN borrows ON borrows.item_id = items.id AND return_date IS NULL
LEFT JOIN borrowers ON borrowers.id = borrows.borrower_id
Something like this should do the trick:
select Items.title,
case
when b1.return_date is null then b2.first_name || ' ' || b2.last_name
else null
end as 'Borrower name'
from Items i
join Borrows b1 on b1.item_id = i.id
join Borrowers b2 on b2.id = b1.borrower_id
This always selects the title of the item, and concats the first_name and last_name of the borrower, but only if return_date is null. Otherwise, null is selected as 'Borrower name'
You can do this with a LEFT OUTER JOIN onto the Borrowers table on the condition that the return_date IS NULL.
This should work for you:
Select I.*,
B.First_Name,
B.Last_Name
From Borrows W
Join Items I On W.item_id = I.Id
Left Join Borrowers B On W.borrower_id = B.id
And W.return_date Is Null
I have a mysql table named "category". the basic structure looks like this-
------ -------- ------
cat_id cat_name parent
------ -------- ------
1 test1 NULL
2 test2 NULL
3 test3 2
4 test4 1
5 test5 3
now i want all the category data with parent category name (not only id) in a single query. is that possible? i could do it by using a second query (getting child's parent name) in a while loop and merging data as a whole. but is it possible to do this with a single query?
Join the table with itself, using the parent column to link to the cat_id of the parent.
SELECT c1.cat_id as childID, c1.cat_name ChildName, c2.cat_name as ParentName
from category c1
LEFT OUTER JOIN category c2
ON c1.parent = c2.cat_id
Be careful: since some elements have no parents (NULL), I put a LEFT
OUTER JOIN so those rows are displayed as well. If you don't want
that, use a JOIN instead of LEFT OUTER JOIN.
You can also show the lines, but display something else (empty or a
text or ...) instead of the NULL by using COALESCE.
You can consider the result as one (big) new table, so you can add WHERE clauses as you usually do, for example filtering on the parent name: WHERE c2.cat_name = 'test2'
Select p.cat_id, p.cat_name, c.cat_id, c.cat_name, c.parent
From category Left Join category On p.cat_id = c.parent
Where p.cat_name = 'name'
SELECT c1.category_name AS category, c2. category_name AS sub_category
FROM (
SELECT *
FROM category
) AS c1
INNER JOIN (
SELECT *
FROM category
) AS c2 ON c1.category_id = c2.category_id