Order of join conditions important? - mysql

Consider this query
SELECT users.id,
users.name
FROM users
LEFT JOIN suppliers
ON users.id = suppliers.id
AND users.hall = suppliers.hall
WHERE USER.payment > 300
In this how will the change of order in the conditions of join matter ( i.e. id second and hall first)?

The order of the Join conditions has no effect on the result since they represent a boolean expression which is analysed in whole.

Related

Data duplicate after join of four tables in Windows Form c# with MS Access

I am joining four tables i.e
users have user_history which workshop he is attending, so as room history where he is staying joining with room is to get name of the room which he is staying
Here is the query that is generate after joining above four tables in Ms Access query Design
SELECT
users.ID,
users.user_name,
users.father_name,
users.phone,
users.email,
users.cnic,
users.address,
users.user_type,
users.department,
users.designation,
users.emergency_no,
users.img,
room_history.ID,
room_history.room_id,
room_history.occupant_id,
room_history.start_date,
room_history.end_date,
rooms.room_name,
user_history.ID,
user_history.workshop
FROM (users
INNER JOIN (rooms
INNER JOIN room_history
ON rooms.room_id = room_history.room_id)
ON users.ID = room_history.occupant_id)
INNER JOIN user_history
ON users.ID = user_history.user_id;
Now the problem is that query works fine, but if user have multiple record in room_history and user_history table it returns four records i.e
In mysql this duplication is fixed by "GROUP BY" clause, that's not working here
I try to add "GROUP BY" to all fields it still cant work.
Note:
Üsers.Img data type is ole object so we cant add GROUP BY to it
Here is my query with GROUP BY clause, Still the result is same
SELECT DISTINCT
users.ID,
users.user_name,
users.father_name,
users.phone,
users.email,
users.cnic,
users.address,
users.user_type,
users.department,
users.designation,
users.emergency_no,
room_history.ID,
room_history.room_id,
room_history.occupant_id,
room_history.start_date,
room_history.end_date,
rooms.room_name,
user_history.ID,
user_history.workshop,
user_history.user_id
FROM (users
INNER JOIN (rooms INNER JOIN room_history ON rooms.room_id = room_history.room_id) ON users.ID = room_history.occupant_id)
INNER JOIN user_history ON users.ID = user_history.user_id
GROUP BY
users.ID,
users.user_name,
users.father_name,
users.phone,
users.email,
users.cnic,
users.address,
users.user_type,
users.department,
users.designation,
users.emergency_no,
room_history.ID,
room_history.room_id,
room_history.occupant_id,
room_history.start_date,
room_history.end_date,
rooms.room_name,
user_history.ID,
user_history.workshop,
user_history.user_id;
My comment captured part of what I wanted to say, but it's hard to articulate that in a tweet.
In essence, GROUP BY and/or SELECT DISTINCT, even if they work, are kind of masking the problem. The problem is that there are four records, and you want to pick one of them. If there is any distinction in the records, this won't work. More importantly, I think it's important that when you do this, and you want one record, you specify which record you want.
Let's assume, in your example if the room_history has multiple records for one occupant/room that you only want the most recent stay. In that case, assuming your DBMS supports the with clause and windowing functions, this would get you that:
with most_recent_history as (
select
ID, room_id, occupant_id, start_date, end_date,
max (end_date) over (partition by room_id, occupant_id) as last_date
from room_history
)
SELECT
users.ID,
users.user_name,
users.father_name,
users.phone,
users.email,
users.cnic,
users.address,
users.user_type,
users.department,
users.designation,
users.emergency_no,
users.img,
h.ID,
h.room_id,
h.occupant_id,
h.start_date,
h.end_date,
rooms.room_name,
user_history.ID,
user_history.workshop
FROM
users
INNER JOIN rooms
INNER JOIN most_recent_history h on
rooms.room_id = h.room_id and
users.ID = h.occupant_id and
h.end_date = h.last_date
INNER JOIN user_history on
users.ID = h.user_id;
If your DBMS does not support windowing functions and/or with, there are other ways to do this, but they're a lot more clumsy. If this is Oracle, SQL Server or PostgreSQL, this will work for sure.
Also, it doesn't seem possible in the real world, but in the event there can be a tie (a person is in two rooms that end on the exact same date), then you can add the tiebreaker to windowing function and use row_number instead.

MySQL - join two tables, group and count

I have two tables:
reviewStatusPhases - id|name
and
userPhase - id|reviewStatusPhase_id|user_id|created_at|updated_at
The reviewStatusPhases table have records inserted (Active, Inactive, On Pause, Terminated...), and userPhase is empty.
The tables are connected via
userPhase.reviewStatusPhase_id = reviewStatusPhases.id
one to one.
Is it possible that in one query I get all reviewStatusPhases, and cound how many users are in each phase? In this case I will get something like this:
Active (0 Users)
Inactive (0 Users)
On Pause (0 Users)
Terminated (0 Users)
I'm making some assumptions here (e.g. INNER JOIN versus LEFT JOIN in the join, and DISTINCT in the count), but it sounds like you just want
SELECT reviewStatusPhases.name, COUNT(DISTINCT userPhase.user_id)
FROM userPhase INNER JOIN reviewStatusPhases
ON userPhase.reviewStatusPhase_id = reviewStatusPhases.id
GROUP BY reviewStatusPhases.name
Query will be as follows:
SELECT r.name as `name`, count(u.id) as `count` FROM reviewStatusPhases r LEFT OUTER JOIN userPhase u ON r.id = u.reviewStatusPhase_id GROUP BY r.name
left outer join with reviewStatusPhases on left to show all names.
group by names of reviewStatusPhases.
display reviewStatusPhases name and count of user id's (to neglect null values)
Use LEFT JOIN as follows:
SELECT COUNT(m.UserId) FROM Table1 m
LEFT JOIN Table2 k ON k.StatusId = m.StatusId
WHERE k.Status = 'Inactive'
You can easily use the Status column to track the users and their activities. In your case, ReviewStatus.
I hope the following will be helpful
SELECT RPS.Name, COUNT(UP.user_id)
FROM reviewStatusPhases RPS
LEFT OUTER JOIN userphases UP ON RPS.id = UP.reviewStatusPhase_id
GROUP BY RPS.Name
ORDER BY RPS.Name
SELECT
DISTINCT s.s_level AS 'Level',
COUNT(DISTINCT s.s_id) AS Schools,
COUNT(DISTINCT st.st_id) AS Teachers
FROM schools AS s
JOIN school_teachers AS st ON st.st_school_idFk = s.s_id AND st.st_status = 1
WHERE s.s_status = 1
GROUP BY s.s_level

Alias not working in query

I need to display the name of the user and their department who has raised the maximum number of queries. I wrote the following query by joining 5 tables; user, query, profile, degree, and department.
The problem is in the result the alias is not being used for the column names. For both the columns it appears as just name
select user.name 'USER_NAME',department.name 'DEPT_NAME'
from user
inner join query on (query.user_id=user.id)
inner join profile on (user.profile_id=profile.id)
inner join degree on (profile.degree_id=degree.id)
inner join department on (degree.department_id=department.id)
group by user.name
order by count(query.id) desc
limit 1
Use 'as' keyword in order to use alias name in mysql and also remove single quotes.
select user.name as USER_NAME from user;
The following syntax work perfectly for me :
select U.name AS "USER_NAME", D.name AS "DEPT_NAME"
from user U
inner join query Q on (Q.user_id=U.id)
inner join profile P on (U.profile_id=P.id)
inner join degree C on (P.degree_id=C.id)
inner join department D on (C.department_id=D.id)
group by U.name
order by count(Q.id) desc
limit 1;
Sometimes, Mysql prefer you pout an alias on your column when you use some JOIN.
Try it this way;
select thisuser.name 'USER_NAME',department.name 'DEPT_NAME'
from user as thisuser
inner join query on (query.user_id=thisuser.id)
inner join profile on (thisuser.profile_id=profile.id)
inner join degree on (profile.degree_id=degree.id)
inner join department on (degree.department_id=department.id)
group by thisuser.name
order by count(query.id) desc
limit 1
but this is not a good practice when constructing a query;
it looks like this
select thisuser.name,thisdept.name from
(select name,user_id from user) as thisuser
inner join
(select name,user_id from department) as thisdept
on thisuser.user_id = thisdept.user_id
Simply remove the quotes from your query and it will work, but you could use the keyword AS to make it clear that you're using an alias.
I would also use lower case aliases in order to avoid confusion with keywords, and also use uppercase for keywords;
SELECT user.name AS user_name, department.name AS dept_name
...

Match results in multiple tables MYSQL

Hi I have a query that is giving me a few problems and it was suggested I ask a separate question about the end result rather than the problem.
So I have three tables and some user input.
the tables are:
users,
usersLanguages and
usersSkills
each table has a related ID the users table has ID and on the other two they have userID to match skills and languages to users
the user input is dynamic but for example it can be 1 for usersLanguages and 2 for usersSkills
The user input is taken from a form and what i need to do is match get the results of users
depending on the language IDs or skill ids passed through. for example i can pass two user ids and three language ID's.
SELECT DISTINCT users.ID, users.name
FROM users
INNER JOIN usersSkills
ON users.ID = usersSkills.userID
INNER JOIN usersLanguages ON users.ID = usersLanguages.userID
WHERE activated = "1"
AND type = "GRADUATE" AND usersSkills.skillID IN(2)
AND usersLanguages.languageID IN(2)
GROUP BY usersSkills.userID HAVING COUNT(*) = 1,
usersLanguages.userID HAVING COUNT(*) = 1
You do not mix group by and having clauses.
having is not a part of group by, in fact you can have having without a group by, in which case it will work as a more capable (and slower) where clause.
SELECT u.ID, u.name
FROM users u
INNER JOIN usersSkills us ON u.ID = us.userID
INNER JOIN al ON u.ID = ul.userID
WHERE u.activated = '1'
AND u.type LIKE 'GRADUATE' AND us.skillID IN('2')
AND ul.languageID IN('2')
GROUP BY u.ID
HAVING COUNT(*) = 1
because of the join criteria, ul.userID = us.userID = u.ID so it makes no sense to group by both. Just group by u.id, because that's the ID you select after all.
u.name is functionally dependent on ID, so that does not need to be listed (*).
When doing a test like u.type = 'GRADUATE', I prefer to do u.type LIKE 'GRADUATE' because LIKE is case insensitive and = may not be depending on the collation, but that's just me.
Distinct is not needed; group by already makes the results distinct.
Having works on the resultset up to and including group by, so in this case you need only one having clause. If you want to have more, you need to treat them the same as a where clause:
having count(*) = 1 AND SUM(money) > 10000
(*) this is only true in MySQL, in other SQL's you need to list all non-aggregated selected columns in your group by clause. Whether they are functionally dependent on the group by column or not. This slows things down and makes for very long query-syntax, but it does prevent a few beginners errors.
Personally I like the MySQL way of doing things.
something like
SELECT * from users left join usersLanguage on users.id=usersLanguage.userID
left join usersSkills on usersSkills.userID=users.id
where usersLanguage.id in (1, 2, 3) and usersSkills.id in (1, 2, 3)
GROUP BY users.id
will probably work
try this
SELECT users.ID,user.name
FROM users
INNER JOIN usersSkills ON users.ID = usersSkills.userId
INNER JOIN AND usersLanguages ON users.ID = usersLanguages.userID
WHERE activate = '1'
AND type = 'GRADUATE'
AND usersSkill.skillID IN (2)
AND usersLanguages.languageID IN (2)
GROUP BY users.ID

Count() using Where clause and Left Join

I have a query similar to the following:
SELECT
users.id FROM users LEFT JOIN sales ON installations.customer = users.id
What I would like to say is something like "WHERE count(sales.id) > 4" - meaning that if the user has more than 4 sales assoc with them. I am not sure if I am going about this the wrong way or not though
select
users.id
from users
join sales on /* your join condition here */
group by users.id
having count(sales.id) > 4
This will group all of the sales by user, then return only those sales that have more than four records in the sales table.
I didn't duplicate your join condition from above because it didn't seem to make much sense, as it's referencing tables that aren't in your query anywhere.
I think you want something similar to this
select users.id, count(sales.id)
from users
LEFT JOIN sales ON installations.customer = users.id
group by users.id
having count(Sales.id) > 5
You need to use "group by" and "having" clause.
Try
SELECT users.id FROM users LEFT JOIN sales ON installations.customer = users.id GROUP BY users.id HAVING count(sale.id) > 4
See here for more GROUPBY on W2C