How to Merge Two Select Query in Mysql - mysql

I have below table structure in my users table where user and driver are saved with a unique id and separated with user_type column. user ratings are being saved in rider_avg_ratings column and driver ratings are being saved in driver_avg_ratings column.
when a user submit a request it is being saved in requesttable with both userid and nearby driver id. now I have to return both driver ratings and user ratings from users table in a single query.Problem is when I join request.userid=users.id it is returning rider_avg_ratings to get the driver_avg_ratings i need to join users.id=request.driver_id how can I get both user and driver ratings from a single query
From above two table by joinning request.user_id=users.id I need to return driver_avg_ratings=4.38 and rider_avg_ratings=1.25

SELECT r.user_id as userId, u.rider_avg_ratings as ratings
FROM user as u
INNER JOIN request as r on u.id = r.user_id
UNION
SELECT r1.driver_id as userId, u1.driver_avg_ratings as ratings
FROM user as u1
INNER JOIN request as r1 on u1.id = r1.driver_id
This query will fetch the desired result.

Your union query should produce a The used SELECT statements have a different number of columns error. You need to figure out why your code isn't checking for errors and make it do so. Also, if this is the entire statement, the parentheses around it don't belong.
You need to make the two unioned selects return the same number of parameters. Note that as in the second select's select columns will be ignored and result column names will come from the first select only. Minimally, to make the query run, you would need to add ,NULL,NULL,... to your second select, but it seems likely you want more information to be able to identify which user the driver_avg_ratings is for, like the id, name, etc the first query is returning.
It's often helpful when processing the results to add something indicating which select a row came from, too, e.g. SELECT "pending_request_users" AS type, ... UNION ALL SELECT "all_users_avg_rating", ....
Note that the different SELECTs unioned together return entire rows. If your only goal is to add driver ratings to the rows already returned, you don't want a union, you may just want to add:
SELECT ..., driver.driver_avg_ratings
FROM user u
...
INNER JOIN user AS driver ON driver.id=req.driver_id
(or left join if there may not be a driver_id). But it's hard to tell for sure if that's what you want. Provide sample data and your desired results from it. In any case, do make your code detect errors properly.

for example:
Department
1 A
2 B
3 A
4 C
5 B
6 D
7 E
8 F
You could do something like
SELECT
1 AS Deptnumber
, Dept
FROM tbl_students
WHERE Dept IN ('A', 'B', 'C')
UNION
SELECT
2 AS DeptNumber
, Dept
FROM tbl_students
WHERE Dept IN ('D', 'E')
UNION
SELECT
3 AS Deptnumber
, Dept
FROM tbl_students
WHERE Dept IN ('F')

Related

SQL select users that belong to two groups

I have a list of persons in a table. I then have another table where I correlate each person to one or more groups. Some persons have only one entry in the groups table but some have multiple.
I am now trying to SELECT list of persons that are in two specific groups. Person must be in BOTH groups in order to qualify.
My table with the basic information on the persons is base and the table with the group correlation is groups_registration. In fact I also have a third table where the groups names and further information are stored but it is not required for this query.
The groups I am trying to gather in this example are 4 and 11.
What I tried initially was:
SELECT base.*, groups_registration.person_id, groups_registration.group_id
FROM base
INNER JOIN groups_registration
ON base.id = groups_registration.person_id
WHERE (groups_registration.group_id = '4' AND groups_registration.group_id = '11')
ORDER BY base.name
This did not get my any response, I assume because no single row contains both group_id = 4 and group_id 11.
I have been searching through stackoverflow with no joy. Do you guys have any ideas?
Obviously, no row has both values. Use group by:
SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2;
I'll let you figure out how to join in the additional information from base.
Notes:
Use table aliases to make it easier to write and read queries.
Presumably, the ids are numbers. Compare numbers to numbers. Only use single quotes for date and string constants.
IN is better than long chains of OR/=.
You can use joins as shown below:
SELECT A.*, B.person_id, B.group_id
FROM base A
INNER JOIN
(SELECT gr.person_id, groups_registration.group_id
FROM groups_registration gr
WHERE gr.group_id IN (4, 11)
GROUP BY gr.person_id
HAVING COUNT(DISTINCT gr.group_id) = 2) B
ON A.id = B.person_id;
This will give you all the desired fields.

mySQL - How to use a COUNT() statement in a JOIN

In a mySQL DB there is a table named clients. Each client row has a column client_num. To list all clients I simply use this statement.
SELECT * FROM clients
Now each client may have or may have not some numbers of subclients which is listed in a seperate table named subclients and referenced through the foreign key client_num in the table.
To find out how many subclient a client may have I can query the subclient table in a seperate call like this: Lets say we have a client with the client_num 254.
SELECT count(1) FROM subclients WEHRE sublicents.client_num = 254
So the query returns something like 0, 1, 2, 3 , n
In a JOIN I assume I have to do something like this :
SELECT
c.*,
sc.?????
FROM clients AS c
LEFT JOIN subclients AS sc ON sc.client_num = 254
But I do not know how to incorporate the count() statement in the JOIN for the amount of subclients. Also I do not know if LEFT JOIN is correct.
Any help is appreciated
EDIT :
I must add that I expect all rows to be returned from clients. The additional returned column COUNT(sc.client_num) carries than the amount of subclients. In the Answer 2 below I get only those clients returned which have subclients. Clients which do not have subclients are not returned. How to fix that ?
You can use the following query to get the count of all sub-clients for each client:
SELECT
c.*,
COUNT(sc.client_num)
FROM clients AS c
LEFT JOIN subclients AS sc ON sc.client_num = c.client_num
WHERE c.client_num = 254
GROUP BY sc.client_sum
solution using a sub-select:
SELECT *, (SELECT COUNT(*) FROM subclients WHERE client_num = clients.client_num)
FROM clients
WHERE client_num = 254
demo: http://sqlfiddle.com/#!9/4930a/8/1
The solution I read from a similar query on Stack Overflow was to use a sub-select. If your only purpose of the join is to Count I would suggest that the join is unneeded. So that:
SELECT clients.*, (SELECT COUNT(*) FROM subclients
WHERE subclients.client_num = clients.id ) AS numb FROM clients WHERE ....
And then for a row of clients, they will have a column numb which will be number of subclients that that client has.
A reference.

Retrieving data from 3 Mysql tables

Suppose I have 3 different tables relationships as following
1st is tbl_users(id,gender,name)
2nd is tbl_feeds(id,user_id,feed_value)
3rd is tbl_favs(id,user_id,feed_id)
where id is primary key for every table.
Now suppose I want to get data where those feeds should come which is uploaded by Gender=Male users with one field in every row that should say either the user who is calling this query marked that particular feed as favourite or not.
So final data of result should be like following :
where lets say the person who is calling this query have user_id=2 then is_favourite column should contain 1 if that user marked favourite that particular feed otherwise is_favourite should contain 0.
user_id feed_id feed_value is_favourite gender
1 2 xyz 1 M
2 3 abc 0 M
3 4 mno 0 M
I hope you getting my question , I m able to get feeds as per gender but problem is I m facing problem to get is_favourite flag as per particular user for every feed entry.
I hope some one have these problem before and I can get help from those for sure.
I would be so thankful if some one can resolve my this issue.
Thanks
Something like this should work:
SELECT
u.id AS user_id.
fe.id AS feed_id,
fe.feed_value,
IFNULL(fa.is_favourite, 0),
u.gender
FROM
tbl_users u
JOIN
tbl_feeds fe ON (fe.user_id = u.id)
LEFT JOIN
tbl_favs fa ON (
fa.user_id = u.id
AND
fa.feed_id = fe.id
)
In order to link your tables, you need to find the most common link between them all. This link is user_id. You'll want to create a relationship between all tables with JOIN in order to make sure each and every user has data.
Now I don't know if you're planning on making sure all tables have data with the user_id. But I would use INNER JOIN as it will ONLY show records of that user_id without nulls. If the other tables could POSSIBLY (Not always guaranteed) you should use a LEFT JOIN based on the tables that is it possible with.
Here is an SQLFiddle as an example. However, I recommend you name your ID fields as appropriate to your table's name so that way, there is no confusion!
To get your isFavorite I would use a subquery in order to validate and verify if the user has it selected as a favorite.
SELECT
u.userid,
u.gender,
f.feedsid,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u
INNER JOIN
tbl_feeds f
ON
u.userid = f.userid
~~~~EDIT 1~~~~
In response to your comment, I have updated the SQLFiddle and the query. I don't believe you really need a join now based on the information given. If you were to do a join you would get unexpected results since you would be trying to make a common link between two tables that you do not want. Instead you'll want to just combine the tables together and do a subquery to determine from the favs if it is a favorite of the user's.
SQLFiddle:
SELECT
u.userid,
f.feedsid,
u.name,
u.gender,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u,
tbl_feeds f
ORDER BY
u.userid,
f.feedsid

MySQL - 3 tables, is this complex join even possible?

I have three tables: users, groups and relation.
Table users with fields: usrID, usrName, usrPass, usrPts
Table groups with fields: grpID, grpName, grpMinPts
Table relation with fields: uID, gID
User can be placed in group in two ways:
if collect group minimal number of points (users.usrPts > group.grpMinPts ORDER BY group.grpMinPts DSC LIMIT 1)
if his relation to the group is manually added in relation tables (user ID provided as uID, as well as group ID provided as gID in table named relation)
Can I create one single query, to determine for every user (or one specific), which group he belongs, but, manual relation (using relation table) should have higher priority than usrPts compared to grpMinPts? Also, I do not want to have one user shown twice (to show his real group by points, but related group also)...
Thanks in advance! :) I tried:
SELECT * FROM users LEFT JOIN (relation LEFT JOIN groups ON (relation.gID = groups.grpID) ON users.usrID = relation.uID
Using this I managed to extract specified relations (from relation table), but, I have no idea how to include user points, respecting above mentioned priority (specified first). I know how to do this in a few separated queries in php, that is simple, but I am curious, can it be done using one single query?
EDIT TO ADD:
Thanks to really educational technique using coalesce #GordonLinoff provided, I managed to make this query to work as I expected. So, here it goes:
SELECT o.usrID, o.usrName, o.usrPass, o.usrPts, t.grpID, t.grpName
FROM (
SELECT u.*, COALESCE(relationgroupid,groupid) AS thegroupid
FROM (
SELECT u.*, (
SELECT grpID
FROM groups g
WHERE u.usrPts > g.grpMinPts
ORDER BY g.grpMinPts DESC
LIMIT 1
) AS groupid, (
SELECT grpUID
FROM relation r
WHERE r.userUID = u.usrID
) AS relationgroupid
FROM users u
)u
)o
JOIN groups t ON t.grpID = o.thegroupid
Also, if you are wondering, like I did, is this approach faster or slower than doing three queries and processing in php, the answer is that this is slightly faster way. Average time of this query execution and showing results on a webpage is 14 ms. Three simple queries, processing in php and showing results on a webpage took 21 ms. Average is based on 10 cases, average execution time was, really, a constant time.
Here is an approach that uses correlated subqueries to get each of the values. It then chooses the appropriate one using the precedence rule that if the relations exist use that one, otherwise use the one from the groups table:
select u.*,
coalesce(relationgroupid, groupid) as thegroupid
from (select u.*,
(select grpid from groups g where u.usrPts > g.grpMinPts order by g.grpMinPts desc limit 1
) as groupid,
(select gid from relations r where r.userId = u.userId
) as relationgroupid
from users u
) u
Try something like this
select user.name, group.name
from group
join relation on relation.gid = group.gid
join user on user.uid = relation.uid
union
select user.name, g1.name
from group g1
join group g2 on g2.minpts > g1.minpts
join user on user.pts between g1.minpts and g2.minpts

MySQL returning results from one table based on data in another table

Before delving into the issue, first I will explain the situation. I have two tables such as the following:
USERS TABLE
user_id
username
firstName
lastName
GROUPS TABLE
user_id
group_id
I want to retrieve all users who's first name is LIKE '%foo%' and who is a part of a group with group_id = 'givengid'
So, the query would like something like this:
SELECT user_id FROM users WHERE firstName LIKE '%foo'"
I can make a user defined sql function such as ismember(user_id, group_id) that will return 1 if the user is a part of the group and 0 if they are not and this to the WHERE clause in the aforementioned select statement. However, this means that for every user who's first name matches the criteria, another query has to be run through thousands of other records to find a potential match for a group entry.
The users and groups table will each have several hundred thousand records. Is it more conventional to use the user defined function approach or run a query using the UNION statement? If the UNION approach is best, what would the query with the union statement look like?
Of course, I will run benchmarks but I just want to get some perspective on the possible range of solutions for this situation and what is generally most effective/efficient.
You should use a JOIN to get users matching your two criteria.
SELECT
user_id
FROM
users
INNER JOIN
groups
ON groups.user_id = users.users_id
AND groups.group_id = given_id
WHERE
firstName LIKE '%foo'
You don't need to use either a UNION or a user-defined function here; instead, you can use a JOIN (which lets you join one table to another one based on a set of equivalent columns):
SELECT u.user_id
FROM users AS u
JOIN groups AS g
ON g.user_id = u.user_id
WHERE g.group_id = 'givengid'
AND u.firstName LIKE '%foo'
What this query does is join rows in the groups table to rows in the users table when the user_id is the same (so if you were to use SELECT *, you would end up with a long row containing the user data and the group data for that user). If multiple groups rows exist for the user, multiple rows will be retrieved before being filtered by the WHERE clause.
Use a join:
SELECT DISTINCT user_id
FROM users
INNER JOIN groups ON groups.user_id = users.user_id
WHERE users.firstName LIKE '%foo'
AND groups.group_id = '23'
The DISTINCT makes sure you don't have duplicate user IDs in the result.