Select query with MySql left join - mysql

I have 3 table (property, facility, property_facility)
Now I want to get all facilities from facility table alone with property data to given property ID.
I tried it with LEFT JOIN as below. But I cannot get all facilities from facility table.
SELECT property_id
, contract_id
, type_id
, location_id
, beds
, ROUND(price,3) as price
, f.facility_id
, f.name
, pf.facility_id
FROM facility f
LEFT JOIN property_facility pf ON pf.facility_id = f.facility_id AND pf.property_id = 6
LEFT JOIN property p USING(property_id)
WHERE p.property_id = 6
Can anybody tell me how I make this query correctly?

Your WHERE clause is filtering out the facilities that do not match. You will need to switch the USING to ON and do:
FROM facility f LEFT JOIN
property_facility pf
ON pf.facility_id = f.facility_id AND
pf.property_id = 6 LEFT JOIN
property p
ON p.property_id = pf.property_id AND p.property_id = 6
You seem to understand the concept, because you are using the same condition for the first JOIN.
Well, actually, the property_id doesn't change. So, you can just remove the WHERE clause and continue with USING if you prefer.

Related

Select all rows with multiple possible values

I am trying to get all fields from the product table (*) that have the following set of sub_property:
subprop_name=X
subprop_value=Y
I have the following tables :
https://imgur.com/a/y4LGqMI (couldn't upload the picture because the format was not accepted)
So, for an example, if I have two products which has in their sub_property table a entry like this:
subprop_name=X
subprop_value=Y
I would like to return it. As described by the schema, a product can have multiple sub_property entries!
So far, this is what I have:
SELECT prod_id,prod_name from product WHERE product.prod_id IN
(
SELECT property.product_prod_id FROM property WHERE property.prop_id IN
(
SELECT property_prop_id from sub_property WHERE
(
sub_property.subprop_name="Type de scanner" AND sub_property.subprop_value="par transparence"
)
OR
(
sub_property.subprop_name="Pages/minute maximum" AND subprop_value="8.5 pages"
)
)
)
But obviously, it doesn't work because of the 'OR'.
It returns me all items that have one of the set of sub_property instead of all the products that have all the sets of sub_property.
DATABASE HERE
Using JOIN's and an IN for the tupples could be a simple solution for this.
SELECT p.prod_id, p.prod_name
FROM product p
JOIN property AS prop
ON prop.product_prod_id = p.prod_id
JOIN sub_property AS subprop
ON subprop.property_prop_id = prop.prop_id
WHERE (subprop.subprop_name, subprop.subprop_value) IN (
('Type de scanner', 'par transparence'),
('Pages/minute maximum', '8.5 pages')
)
GROUP BY p.prod_id, p.prod_name
So... I am not sure if it's the correct way to validate two answers, but I got 2 working answers.
This is the first one from #Steff Mächtel using LEFT JOIN (https://stackoverflow.com/a/53915792/5454875)
And the second one is from #Shidersz (see comments below the original question), using INNER JOIN)
"I used and approach using INNER JOIN, is something like this what you need? db-fiddle.com/f/t6RrnhDPQuEamjf2bTxFeX/5"
EDIT
#Shidersz solution doesn't work because it selects all products who as at least one of the condition, wich I don't want. I want the product to have all the conditions.
UPDATE 2:
I would suggest to use LEFT JOIN for each property and each sub_property and then check the value inside WHERE condition:
SELECT product.prod_id, product.prod_name
FROM product
LEFT JOIN property AS property_a ON property_a.product_prod_id = product.prod_id AND
property_a.prop_name = "PROPERTY_GROUP_3"
LEFT JOIN sub_property AS sub_property_a ON sub_property_a.property_prop_id = property_a.prop_id AND
sub_property_a.subprop_name="property_4"
LEFT JOIN property AS property_b ON property_b.product_prod_id = product.prod_id AND
property_b.prop_name = "PROPERTY_GROUP_4"
LEFT JOIN sub_property AS sub_property_b ON sub_property_b.property_prop_id = property_b.prop_id AND
sub_property_b.subprop_name="property_3"
WHERE sub_property_a.subprop_value="value_of_property_4" AND
sub_property_b.subprop_value="value_of_property_3"
GROUP BY product.prod_id
Example: https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/6
Example with 2 new "KEYS" (Index) for better performance:
ALTER TABLE `property`
... ADD KEY `prop_name` (`prop_name`);
ALTER TABLE `sub_property`
... ADD KEY `subprop_name` (`subprop_name`);
https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/7
Example with INNER JOIN instead of LEFT JOIN
I see no difference with EXPLAIN on test data, maybe Mysql optimizer handles this internal equal
SELECT product.prod_id, product.prod_name
FROM product
INNER JOIN property AS property_a ON property_a.product_prod_id = product.prod_id AND
property_a.prop_name = "PROPERTY_GROUP_3"
INNER JOIN sub_property AS sub_property_a ON sub_property_a.property_prop_id = property_a.prop_id AND
sub_property_a.subprop_name="property_4" AND
sub_property_a.subprop_value="value_of_property_4"
INNER JOIN property AS property_b ON property_b.product_prod_id = product.prod_id AND
property_b.prop_name = "PROPERTY_GROUP_4"
INNER JOIN sub_property AS sub_property_b ON sub_property_b.property_prop_id = property_b.prop_id AND
sub_property_b.subprop_name="property_3" AND
sub_property_b.subprop_value="value_of_property_3"
GROUP BY product.prod_id
https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/8

MySQL, select, comparing values from 2 tables

in my database I want to select every construction_manual
where storage_room.quantity > component.quantity
But when I use:
SELECT construction_manual.name
FROM construction_manual cm, construction_manual_component cmc, component, storage_room
WHERE cm.ID = cmc.construction_manual_ID
AND cmc.component_ID = component.ID
AND component.storage_room_ID = storage_room.ID
AND storage_room.quantity > component.quantity
It will select every construction_manual.name as long as the first component in the storage_room has enough quantity.
So let's say...
construction_manual.1 needs
component.A -> quantity 5
component.B -> quantity 10
and in the storage room there is:
component.A -> quantity 6
component.B -> quantity 0
Although there is not enough in the storage room, construction_manual.1 will be selected. How do I select only those construction_manuals where there are enough components in the storage_room?
edit:
In my 4 tables are the following datasets. I will get the following result when I use the query mentioned above:database . But I should not be able to construct a table because there are not enough wooden_plates (wooden planks and not wooden plates ofc...ups)
I think what you want to ask is to ignore or exclude any construction manual that does not have enough components to satisfy a build. If that's the case you can do something like the below (a left join would also do it):
select distinct cm.name as construction_manual
from construction_manual cm
join construction_manual_component cmc
on cmc.construction_manual_ID = cm.ID
join component c
on c.ID = cmc.component_ID
join storage_room sr
on sr.ID = c.storage_room_ID
where sr.quantity > c.quantity
and cm.ID not in (select cm.ID
from construction_manual cm
join construction_manual_component cmc
on cmc.construction_manual_ID = cm.ID
join component c
on c.ID = cmc.component_ID
join storage_room sr
on sr.ID = c.storage_room_ID
where sr.quantity < c.quantity);

Simple query issue with multiple tables and mismatching IDs

I'm having trouble with a simple MySQL Query.
Here is the query:
SELECT distinct e.E_CODE, s.S_CODE, p.P_ID, p.P_NAME, p.P_FIRSTNAME, p.P_STATUS, e.E_BOSS, tp.TP_TITLE
from event_participation ep, worker p, type_participation tp, event e, section s
where ep.P_ID = p.P_ID
and s.S_ID = e.S_ID
and ep.TP_ID = tp.TP_ID
and e.E_CODE = ep.E_CODE
The problem is that ep.TP_ID sometimes has a value set to zero while tp.TP_ID has nothing with a zero ID. It's auto-increment and starts at 1 and so on.
The result is obviously that this query does not return records when the ep.TP_ID = 0 and there is no match in tp.TP_ID.
So I'm trying to figure out a way to get those results in there anyway. I was thinking of using a LEFT JOIN statement but couldn't figure out a proper way to insert it into the query.
Any advice on this matter would be greatly appreciated.
First of all, I advice you to use some general type for event_participation records without type; But, unless to take that decision, supposing you want to get all matching records between all tables but also get results with no type, you can use the following query:
SELECT DISTINCT e.E_CODE, s.S_CODE, p.P_ID, p.P_NAME, p.P_FIRSTNAME, p.P_STATUS, e.E_BOSS, tp.TP_TITLE
FROM event_participation ep
JOIN worker p ON (ep.P_ID = p.P_ID)
JOIN event e ON (e.E_CODE = ep.E_CODE)
JOIN section s ON (s.S_ID = e.S_ID)
LEFT JOIN type_participation tp ON (ep.TP_ID = tp.TP_ID)
SELECT DISTINCT e.E_CODE
, s.S_CODE
, p.P_ID
, p.P_NAME
, p.P_FIRSTNAME
, p.P_STATUS
, e.E_BOSS
, tp.TP_TITLE
FROM event_participation ep
JOIN worker p
ON p.P_ID = ep.P_ID
JOIN event e
ON e.E_CODE = ep.E_CODE
JOIN section s
ON s.S_ID = e.S_ID
LEFT
JOIN type_participation tp
ON tp.TP_ID = ep.TP_ID;

SQL: Get latest entries from history table

I have 3 tables
person (id, name)
area (id, number)
history (id, person_id, area_id, type, datetime)
In this tables I store the info which person had which area at a specific time. It is like a salesman travels in an area for a while and then he gets another area. He can also have multiple areas at a time.
history type = 'I' for CheckIn or 'O' for Checkout.
Example:
id person_id area_id type datetime
1 2 5 'O' '2011-12-01'
2 2 5 'I' '2011-12-31'
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31.
Now I want to have a list of all the areas all persons have right now.
person1.name, area1.number, area2.number, area6.name
person2.name, area5.number, area9.number
....
The output could be like this too (it doesn't matter):
person1.name, area1.number
person1.name, area2.number
person1.name, area6.number
person2.name, area5.number
....
How can I do that?
This question is, indeed, quite tricky. You need a list of the entries in history where, for a given user and area, there is an 'O' record with no subsequent 'I' record. Working with just the history table, that translates to:
SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime)
FROM History AS ho
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
)
GROUP BY ho.person_id, ho.area_id, ho.type;
Then, since you're really only after the person's name and the area's number (though why the area number can't be the same as its ID I am not sure), you need to adapt slightly, joining with the extra two tables:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
);
The NOT EXISTS clause is a correlated sub-query; that tends to be inefficient. You might be able to recast it as a LEFT OUTER JOIN with appropriate join and filter conditions:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
LEFT OUTER JOIN History AS hi
ON hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
WHERE ho.type = 'O'
AND hi.person_id IS NULL;
All SQL unverified.
You're looking for results where each row may have a different number of columns? I think you may want to look into GROUP_CONCAT()
SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id`
I haven't tested this query, but I have used group concat in similar ways before. Naturally, you will want to tailor this to fit your needs. Of course, group concat will return a string so it will require post processing to use the data.
EDIT I thikn your question has been edited since I began responding. My query does not really fit your request anymore...
Try this:
select *
from person p
inner join history h on h.person_id = p.id
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O'
inner join areas on a.id = h.area_id
where h2.person_id is null and h.type = 'I'

left join with specific conditions help please

am having a problem constructing a query
here is simplified tables structure
3 tables
Event [Event_id , Event_name]
Event_files [Event_id(FK) , File_id(FK)]
Uploaded_Files[File_id , File_type, File_path]
we mainly have 2 file types
image = 2
document = 4
what am trying to do is to get the events along with their images (if they have an image )
am trying to do this with this Query
select e.id, e.name,uf.id as file_id,uf.path
from event e
left join event_file ef on ef.event_id = e.id
left join uploaded_file uf ON ef.file_id = uf.id
i know that i need to apply a condition but each time i do in the where or ON there is always problem with the Query
for example if i apply :
left join uploaded_file uf ON ef.file_id = uf.id AND (uf.type = 2 )
it will still return 2 records for the events that has both image and file one of them with file_path null .
on the other hand if i do the following :
where (uf.id is null OR (uf.id is not null AND uf.type=2))
the events with only files and no image will not be returned any more
is there is solution please ?
thanks in advance
SELECT e.id, e.name, f.file_id AS file_id, f.path
FROM event e
LEFT JOIN
(
SELECT ef.event_id, uf.id AS file_id, uf.path
FROM event_file ef
INNER JOIN uploaded_file uf ON ef.file_id = uf.id AND uf.type = 2
) f ON f.event_id = e.id
This should do (untested.)
The reason you're getting the empty record is because you only specify the uf.type condition on the uploaded_file table, which imposes nothing on the left join for event_file.