How to use left outer join in mysql to get my desirable results?

妖精的绣舞 提交于 2019-12-13 07:38:51

问题


I have made an sql fiddle. Users with id 100 and 118 should have 0 records for assigned_scopes, assigned_qa, failed_qa and assigned_canvass. But it does not display that data; it just shows the record for the user with id 210. What I really need is to display all the users, with 0 in each column if they have nothing. How can I do this?

What I have tried since is in this fiddle. It works according to my requirements but there is problem with query optimization; its execution time is not what I want. It took more than 33 seconds to load the page (which is not good at all) when I used the second fiddle query because of the huge data. The query in the first fiddle executed in 2 seconds even with huge data. How can correct the first query to give the results of the second query while (hopefully) staying fast?


回答1:


The "ten second explanation" for why most queries with LEFT JOIN do not display rows that you expect is that you've put one of the left joined tables into the where clause, demanding a value. This automatically converts any left join into an inner join behaviour

You either have to say WHERE leftjoinedtable.column =value OR leftjoinedtable.column is null or preferentially put the statement in the ON condition (doesn't need a qualifying 'or xxx is null which makes your query simpler and more readable

Move all the statements in your where clause out, and into the respective ON conditions so your query no longer has a where clause section at all. Throw your latter attempt away; it has a Cartesian join and sub selects in the main selection list; in a production system it could be generating millions more rows than needed, selecting extra data based on them, and then discarding them. A very difficult query style to optimise and usually unnecessary

Edit.. Had another look at your fiddle, noticed you also GROUP BY a column that could be null.. When it is, those rows disappear from the output

In terms of how you should write queries, consider first which tables will always have all the values. In your case these are the user and teams tables. These should be inner joined together first, then other tables which may not always have a matching row should be added LEFT join. Right join is seldom needed

Alter the order of your tables so it's teams, inner join users, then left join the two tables you're counting stars on. When you group by, group on the users Id from the users table, not the stats table

I did this with your fiddles but couldn't find a way to save them as a new fiddle on the iPad, couldn't copy the text, but here's a screenshot of a query that does what you require, I'll leave the typing as an exercise for the reader :) , don't forget to adjust the group by

Note, now the users table is inner joined, the =15 filter could go in the where clause... I'll leave the general advice though, to encourage and remind you that a) it works just as well in the ON clause and b) to prefer putting these things in the ON because it means left joins work as you expect




回答2:


Read a definition of left join on. It returns rows that inner join on does plus unmatched rows in the left table extended by nulls.

Re your 1st link query: If you want all the records from user then it must be the leftmost table in your left joins. You must not remove rows that might have null values by tests requiring non-null values in where--but, why would you?--ie, why do you? The following returns rows only for users with role 15, per the 2nd link query; you don't explain why 15 tested for in the 1st.

select u.user_id,
    ut.name as team_name,
    /* ... */
    count(case when a.status = 2 AND a.qc_id = 0 and o.class_id= 3 then 1 else null end) 
    AS assigned_canvass
from am_user u
left join user_team ut
on u.user_team_id = ut.user_team_id
left join am_ts_assignment a
on u.user_id = a.tech_id
left join am_ts_order o
on o.assignment_id = a.assignment_id
where u.user_role_id = 15
group by u.user_id
order by u.user_id asc

Compose your queries incrementally and test as you add joins & columns.

(This is the same query I gave on your last post re essentially your 1st link query except it returns a row for every am_user instead of every am_ts_assignment, per each post. The where might have been an and in the first left join with am_user; either will do here.)



来源:https://stackoverflow.com/questions/45261775/how-to-use-left-outer-join-in-mysql-to-get-my-desirable-results

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!