MySQL nested join across many tables - mysql

I have table for transactions, transaction_properties, transaction_inventories. inventories.
`transactions:`
id, name, qty
`transaction_properties:`
transaction_id, property_id
`transaction_inventory:`
transaction_id, inventory_id
`inventories:`
id, name, property_id
My task is to get all transaction according my property id.
property_id gets data from inventory that gets data from transaction_inventory, also gets data from transaction_properties and finally I get all transaction_ids to get them from transaction table.
Please do not consider to change table architecture. This style is a must for this project.

Check the following query:
select inv.*,t.*,tran_pro.*,tran_inv.* from inventories as inv
left join on transation as t on t.id on tran_pro.transtaion_id
left join on transaction_properties as tran_pro on t.id = tran_pro.transaction_id
left join on transaction_invertory as tran_inv on t.id = tran_inv.transaction_id
where inv.property_id = ''
Note:Keep all ids as primary key

I don't know, it should be fairly simple if you have attempted to solve the problem or looked up how joins work. Unless I am missing any other detail.
select t.id, t.name, invt.id, tp.property_id
from inventories invt
inner join transactions_inventory ti
on invt.id = ti.inventory_id
inner join transaction_properties tp
on tp.transaction_id = ti.transaction_id
inner join transactions t
on t.id = tp.transaction_id

Related

is it possible, to first join in if condition and second join in Else condition

is it possible in MYSQL
There are three tables
tasks (task_id, task_status, ...)
tasks_assigned_to (ta_id, task_id, user_id)
task_suggested_to (ts_id, task_id, user_id)
users (user_id, ...)
select user_id
if task_status = 2
join task_assigned_to ta on ta.task_id = tasks.task_id
else
join task_suggested_to ts on ts.task_id = tasks.task_id
Here is my sample query what I am trying to.
All kind of answers will be appreciated
Thank you
You can join both, and use the if statement in the fields you select.
This works great in certain data sets/tables, but should be avoided if the join is very slow or if you never need both results.
However if you have a ticked you may want to show both the assignee and the suggested assignee (if it differs).
select
ticket.id
empassign.name assigned,
empsuggested.name suggested,
ifnull(empassigned.name,empsuggested) autoassigned
from
ticket
left join emps empassign on empassign.id=ticket.assignedid
left join emps empsuggested on empassign.id=ticket.suggestedid
Just JOIN both using your condition
SELECT * FROM t
JOIN task_assigned_to ta ON ta.task_id = t.task_id AND t.task_status = 2
JOIN task_sugggested_to ts ON ts.task_id = t.task_id
Here is a fiddle,the general idea is to get all the data with LEFT join and then filter it with a WHERE ts IS NOT NULL and a COLAESCE.. or whatever you need.

MySQL Query limiting results by sub table

I'm really struggling with this query and I hope somebody can help.
I am querying across multiple tables to get the dataset that I require. The following query is an anonymised version:
SELECT main_table.id,
sub_table_1.field_1,
main_table.field_1,
main_table.field_2,
main_table.field_3,
main_table.field_4,
main_table.field_5,
main_table.field_6,
main_table.field_7,
sub_table_2.field_1,
sub_table_2.field_2,
sub_table_2.field_3,
sub_table_3.field_1,
sub_table_4.field_1,
sub_table_4.field_2
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
WHERE sub_table_4.field_1 = '' AND sub_table_4.field_2 = '0' AND sub_table_2.field_1 != ''
The query works, the problem I have is sub_table_1 has a revision number (int 11). Currently I get duplicate records with different revision numbers and different versions of sub_table_1.field_1 which is to be expected, but I want to limit the result set to only include results limited by the latest revision number, giving me only the latest sub_table_1_field_1 and I really can not figure it out!
Can anybody lend me a hand?
Many Thanks.
It's always important to remember that a JOIN can be on a subquery as well as a table. You could build a subquery that returns the results you want to see then, once you've got the data you want, join it in the parent query.
It's hard to 'tailor' an answer that's specific to you problem, as it's too obfuscated (as you admit) to know what the data and tables really look like, but as an example:
Say table1 has four fields: id, revision_no, name and stuff. You want to return a distinct list of name values, with their latest version of stuff (which, we'll pretend varies by revision). You could do this in isolation as:
select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no;
(Note: see fiddle at the end)
That would return each individual name with the latest revision of stuff.
Once you've got that nailed down, you could then swap out
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
....with....
INNER JOIN (select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no) sub_table_1
ON sub_table_1.id = main_table.id
...which would allow a join with a recordset that is more tailored to that which you want to join (again, don't get hung up on the actual query I've used, it's just there to demonstrate the method).
There may well be more elegant ways to achieve this, but it's sometimes good to start with a simple solution that's easier to replicate, then simplify it once you've got the general understanding of the what and why nailed down.
Hope that helps - as I say, it's as specific as I could offer without having an idea of the real data you're using.
(for the sake of reference, here is a fiddle with a working version of the above example query)
In your case where you only need one column from the table, make this a subquery in your select clause instead of than a join. You get the latest revision by ordering by revision number descending and limiting the result to one row.
SELECT
main_table.id,
(
select sub_table_1.field_1
from sub_table_1
where sub_table_1.id = main_table.id
order by revision_number desc
limit 1
) as sub_table_1_field_1,
main_table.field_1,
...
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
WHERE sub_table_4.field_1 = ''
AND sub_table_4.field_2 = '0'
AND sub_table_2.field_1 != '';

How to access parent column from a subquery within a join

I'm trying to left join the second table useri_ban based on the users' ids, with the extra condition: useri_ban.start_ban = max_start.
In order for me to calculate max_start, I have to run the following subquery:
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id)
Furthermore, in order to add max_start to every row, I need to inner join this subquery's result into the main result. However, it seems that once I apply that join, the subquery is no longer able to access useri.id.
What am I doing wrong?
SELECT
useri.id as id,
useri.email as email,
useri_ban.warning_type_id as warning_type_id,
useri_ban.type as type,
useri.created_at AS created_at
FROM `useri`
inner join
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id) `temp`
on `useri`.`id` = `temp`.`user_id`
left join `useri_ban` on `useri_ban`.`user_id` = `useri`.`id` and `useri_ban`.`start_ban` = `max_start`
Does this solve your problem? You need GROUP BY in the inner query instead of another join.
SELECT useri.id, useri.email, maxQuery.maxStartBan
FROM useri
INNER JOIN
(
SELECT useri_ban.user_id ubid, MAX(useri_ban.startban) maxStartBan
FROM useri_ban
GROUP BY useri_ban.user_id
) AS maxQuery
ON maxQuery.ubid = useri.id;

LEFT OUTER JOIN AND WHERE on joining table

To elaborate, I'm selecting fields from item and locations tables. Connection is location_id from items table and id field from locations table. After join I'm doing WHERE statement on city_text field from locations table.
Is this legal action since I'm doing WHERE on field from second table?
SELECT uc_items.* ,
uc_users_store.id AS store_id,
uc_users_store.store_name,
uc_users_store.address,
uc_users_store.work_hours,
uc_locations.city_text AS city,
uc_locations.zipcode_text AS zipcode,
uc_locations.state_text AS STATE,
uc_locations.country_text AS country
FROM uc_items
LEFT OUTER JOIN uc_users_store ON uc_items.store_id=uc_users_store.id
LEFT OUTER JOIN uc_locations ON uc_users_store.store_location_id=uc_locations.id
WHERE uc_locations.city_text LIKE "%'.$city.'%"
AND uc_items.iname LIKE "%'.$description.'%"
AND uc_items.expiration_stamp > '.time().'
ORDER BY uc_items.posting_stamp DESC,
uc_items.discount DESC
It's legal, but might lead to unexpected results if the tested value is NULL. However, you could catch these situations by including an IS NULL check.
For instance
WHERE (col = 'value' OR col IS NULL)
Completely legal. However it would be a lot more logical to use INNER JOIN instead of LEFT JOIN since your WHERE statement is concerning the table you are joining to. A pseudo example:
SELECT t1.something, t2.somethin FROM first_table t1 INNER JOIN second_table t2 ON t1.some_id = t2.some_id_from_t1 WHERE t2.some_column='something'

Latest date from ClassSchedule Table for each class

I have a problem with database query?
Here is the Scenario
This is a TeacherClass Table (Parent Table)(id)
And This is a ClassSchedule Table(Child table)(teacher_class_id is a foreign key)
I want to find out the the latest date from ClassSchedule Table for each class and order by class_schdule_date(latest date).
(It would be better for me if you write the query in cackphp query syntax.)
Please Help me.
This requires a straightforward join:
select tc.id, max(schedule_date) as max_schedule_date
from TeacherClass tc
left join ClassSchedule cs on cs.teacher_class_id = tc.id
group by tc.id
You can select other columns from the TeacherClass table as you like - just add them to the group by clause too.
Note that left join is required in case there are no scheduled dates for the class, you still get a row for the class (but the max scheduled date will be null)
Use this solution:
SELECT
c.*, b.*
FROM
(
SELECT teacher_class_id, MAX(schedule_date) AS maxdate
FROM classschedule
GROUP BY teacher_class_id
) a
INNER JOIN
classschedule b ON
a.teacher_class_id = b.teacher_class_id AND
a.maxdate = b.schedule_date
INNER JOIN
teacherclass c ON
b.teacher_class_id = c.teacher_class_id