简体   繁体   中英

How to select column from 2nd level depth subquery?

I have found a few answers how to select a column from subquery, but it doesn't seem to be working if there is a subquery inside subquery.

My table relationships are as follow (simplified, with example):

Plans
| id | role_id
| --------------
| 4  | 2

Roles
| id | name
----------------
| 2  | Operator

Assignments
| role_name | user_id
| ---------------------
| Operator  | 12

Table Plans have foreign key role_id to table Roles column id . And Table Roles have foreign key id to table Assignments column role_name .

I'm writing a query that would select Plans but instead of role_id I would show user_id from table Assignments .

I'm pretty close with my current work but I'm stuck at final step:

SELECT assigned_user, plan.id, plan.role_id
FROM `Plans` AS plan
LEFT JOIN (
    SELECT roleTable.id, roleTable.name 
    FROM `Roles` AS roleTable
    INNER JOIN (
        SELECT base_assign.user_id AS assigned_user, base_assign.role_name 
        FROM `Assignments` AS base_assign) AS roleAssign
    ON roleTable.name = roleAssign.role_name
) AS role 
ON (plan.assignee_role = role.id)

Column assigned_user on SELECT part (line 1) is not found but I tried by adding alias inside of subquery SELECT . How I can select base_assign.user_id ? Note that I (most likely) cannot modify database structure as it was given like this in the first place.

You are creating subqueries too excessively and you don't even need subqueries for this. Subqueries can be materialized by optimzer in MySQL which can cause performance issues.

See https://dev.mysql.com/doc/refman/5.6/en/subquery-optimization.html

Try this using simple left join s:

select a.user_id as assigned_user,
    p.id,
    p.role_id
from `Plans` p
left join `Roles` r on p.assignee_role = r.id
left join `Assignments` a on r.name = a.role_name;

You query wasn't working because you were not selecting the column while joining.

Your somewhat "fixed" code:

select assigned_user,
    plan.id,
    plan.role_id
from `Plans` as plan
left join (
    select roleAssign.assigned_user roleTable.id,
        roleTable.name
    from `Roles` as roleTable
    inner join (
        select base_assign.user_id as assigned_user,
            base_assign.role_name
        from `Assignments` as base_assign
        ) as roleAssign on roleTable.name = roleAssign.role_name
    ) as role on (plan.assignee_role = role.id)

You don't need subqueries for this. It is a little confusing what you are trying to do. The following will return all plans, even those with no roles and no assignments :

SELECT b.user_id as assigned_user, p.id, p.role_id
FROM Plans p LEFT JOIN
     Roles r
     ON p.role_id = r.id LEFT JOIN
     Assignments a
     ON a.name = r.name;

Subqueries are bad for two reasons. In MySQL, the are materialized. That means extra overhead for reading and writing the tables. Plus, you lose any indexes on them.

In your case, the subqueries just add layer upon layer of naming, and the names really do not help make your query more understandable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM