How to get hobbies in student lists with subquery mysql - mysql

well, i have 100 student lists and every student has more than a hooby.
i have 2 tables,
table name = students
attribute = student_id,name,dob,address
and
table name = hobbies
attribute = hobby_id, student_id, hoby_name.
how do i get result like below.
.student_id | name | dob | address | hobby.
1 | Jordan | 12-12-1998 | 23 avenue |reading, dota2, football
2 | Bela | 13-01-1997 | 12 hills |swimming, badminton
3 | Jack | 01-02-1999 | 07 clinton|dota2
once i try to use subquery it says "subquery returns more than 1 row".
thank u guys.

select sa.student_id,name,dob,address, GROUP_CONCAT(hoby_name)
from students_attribute sa
left join hobbies_attribute ha
on sa.student_id = ha.student_id
group by sa.student_id
This will provide to required result.

Related

My query is missing a row that has a zero

I searched for an answer to this but didn't find one for this specific problem. I am making a database for storing classes created by a teacher, and a lookup table for students enrolled in each class. I want to run a query that shows each teacher's class and the number of students. As you can see in the data below, the teacher has two classes with zero students, but only one of them is returning in the query.
The query:
SELECT `c`.`ClassID` AS `id`,
`c`.`Class_Name` AS `name`,
`c`.`Class_Code` AS `code`,
COUNT(`e`.`EnrollID`) AS `count`
FROM `CMP_Classes` `c`
LEFT OUTER JOIN `CMP_Student_Enrollment` `e`
ON `c`.`ClassID` = `e`.`Enroll_ClassID`
AND `Class_Teacher` = 1
GROUP BY `e`.`EnrollID`
The data:
CMP_Classes Table:
ClassID | Class_Name | Class_Code | Class_Teacher
1 | Mr. Jones' 1st Period Class | QYTNPCGK | 1
2 | Mr. Jones' 2nd Period Class | HZWNDZPM | 1
3 | Pizza | RRCXQNNE | 9
4 | Mr. Jones' 3rd Period Class | NFLBXFEQ | 1
CMP_Student_Enrollment Table:
EnrollID | Enroll_Student | Enroll_ClassID
3 | 2 | 1
Query results:
id | name | code | count
2 | Mr. Jones' 2nd Period Class | HZWNDZPM | 0
1 | Mr. Jones' 1st Period Class | QYTNPCGK | 1
So, as you can see, there is no row for "Mr. Jones' 3rd Period Class" but there should be.
You need to group by the unaggregated columns in the select:
SELECT c.ClassID AS id, c.Class_Name AS name, c.Class_Code AS code,
COUNT(e.EnrollID) AS `count`
FROM CMP_Classes c LEFT OUTER JOIN
CMP_Student_Enrollment e
ON c.ClassID = e.Enroll_ClassID
WHERE c.Class_Teacher = 1
GROUP BY c.ClassID, c.Class_Name, c.Class_Code;
All the backticks in your query make it harder to read and write.

How to get all data from a table which you also query for AVG

Hello I need help on solving the query problem below.. Thanks in advance.
I have three tables
attachments
sun_individual
sun_reviews
I want to select user names, profession and reviewed by his/her ID from sun_individual and join with his profile photo from table attachments then get his/her reviews (each review and rate) and the average RATE
TABLE : sun_individual
id|sun_id|first_name|last_name |sun_profession|sun_verified_date|sun_verified|flg
---------------------------------------------------------------------------------
20|SV-001|Alex | James | Doctor |2017-12-08 | 1 |1
21|SV-002|Jane | Rose | Programmer |2017-12-08 | 1 |1
TABLE: sun_reviews
id|user_id|rev_txt |rev_rate|rev_date |flg
----------------------------------------------------
1 |20 | the best | 4 |2017-12-09|1
2 |21 | know CLI | 2 |2017-12-09|1
3 |20 | recommend| 3 |2017-12-09|0
4 |20 | so far | 3 |2017-12-09|1
TABLE: attachments
id|user|type |path |flg
----------------------------------------
88|20 |passport|/upload/img128.jpg|1
89|21 |passport|/upload/img008.jpg|1
flg:1 means the value is active, flg:0the value is to be ignored
My Code is :
SELECT
sun_reviews.rev_txt As txtReview, sun_reviews.rev_date As dateReview,
sun_reviews.rev_rate As rateReview,
AVG(sun_reviews.rev_rate) As avgREV,
concat(sun_individual.first_name, sun_individual.last_name) As name,
sun_individual.sun_profession As profession,
sun_individual.sun_verified_date As dateVerified,
CASE when sun_verified = 1 then 'VERIFIED' else 'EXPIRED' END As status,
attachments.path As photo
FROM `sun_individual`
LEFT JOIN sun_reviews ON sun_reviews.user_id = sun_individual.id
INNER JOIN attachments ON attachments.user = sun_individual.id
WHERE attachments.type = 'passport' AND attachments.flg = 1
AND sun_reviews.flg = 1 AND sun_individual.flg = 1
AND sun_individual.sun_id LIKE '%SV-001'
What I want to archive is when someone is looking for user (let say SV-001) when the code is inputted to get result like
result for: SV-001
txtReview|dateReview|rateReview|avgREV|name |profession | dateVerified | photo
------------------------------------------------------------------------- -----------------
the best |2017-12-09|4 |3.5000|Alex James| Doctor | 2017-12-08 |/upload/img128.jpg
so far |2017-12-09|3 |3.5000|Alex James| Doctor | 2017-12-08 |/upload/img128.jpg
I want to get result like the one above, however when I ran the query I get only one review
txtReview|dateReview|rateReview|avgREV|name |profession | dateVerified | photo
------------------------------------------------------------------------- -----------------
the best |2017-12-09|4 |3.5000|Alex James| Doctor | 2017-12-08 |/upload/img128.jpg
I think there is something am doing wrong... If you know the solution to my problem kindly help me.
Thanks.
select
a.rev_txt as txtReview,
a.rev_date as dateReview,
a.rev_rate as rateReview,
d.avgRev as avgRev,
b.first_name || b.last_name as name,
b.sun_profession as profession,
b.sun_verified_date as dateVerified,
case
when sun_verified = 1 then 'VERIFIED'
else 'EXPIRED'
end as status,
c.path as photo
from
sun_reviews a
join
sun_individual b
on a.user_id = b.id
join
attachments c
on c.user_id = b.id
join
(
select
user_id,
avg(rev_rate) as avgRev
from
sun_reviews
where
flg = 1
group by
user_id
) d
on d.user_id = b.id
where
c.type = 'passport' and
c.flg = 1 and
a.flg = 1 and
b.flg = 1 and
b.sun_id LIKE '%SV-001';
txtreview | datereview | ratereview | avgrev | name | profession | dateverified | status | photo
-----------+------------+------------+--------------------+-----------+------------+--------------+----------+--------------------
the best | 2017-12-09 | 4 | 3.5000000000000000 | AlexJames | Doctor | 2017-12-08 | VERIFIED | /upload/img128.jpg
so far | 2017-12-09 | 3 | 3.5000000000000000 | AlexJames | Doctor | 2017-12-08 | VERIFIED | /upload/img128.jpg
(2 rows)
When you have a group by, all columns in the result set must be either group by columns or aggregates. I guess you are using MySQL which does not enforce this. You should enforce it yourself though, otherwise it gets very confusing.

How to search husband and wife data with one MySQL query?

I'm trying to find the most efficient and optimized way of querying husband and wife data for a search function in a finance application. The clients can be single or married.
Currently, when the data is created, there is a table for the household that shares information such as username, password, address, location, etc...
There is a separate table that stores individual information about the husband and wife in separate rows including birth dates and income.
The app has a search function where a user can search using criteria such as location, husband age range and income range and wife age range and income range and should return individual household results.
For instance, a user can search for clients that are located within 20 miles where the husband is between 50 and 60 years old and the wife is between 40 and 50 years old with an income range of $30,000 to $40,000.
The result would produce all results for singles and couples.
Here is just an idea of what the tables and results may look like. Keep in mind that the location data would actually use lat and long but for the purpose of this example, we are just using actual miles to keep it simple.
Table Users:
ID | Username | Location | Password | Email | Status
-------------------------------------------
1 | singleclient | 5 miles | 24##$#dls | user1#email.com | Single
2 | marriedclient | 7 miles | $#$sls33 | user2#email.com | Married
Table UserDetails
ID | User_ID | Gender | Name | Age | Income
----------------------------------
1 | 1 | Male | John Smith | 55 | 32000
2 | 2 | Male | Mike Jones | 53 | 37000
3 | 2 | Female | Cindy Jones | 47 | 31000
Result:
ID | Username | Distance | Status | Male Name | Female Name | Male Age | Female Age | Male Income | Female Income
----------------------------------------
1 | singleclient | 5 miles | Single | John Smith | null | 55 | null | 32000 | null
2 | marriedclient | 7 miles | Married | Mike Jones | Cindy Jones | 53 | 47 | 37000 | 31000
First, in many countries, the assumption that a marital unit consists of a single male and a single female is not true. I would try to avoid building this assumption into the data model or application.
I think you can approach this question using aggregation with a having clause:
select ud.user_id
from UserDetails ud
group by ud.user_id
having sum(case when ud.gender = 'Male' and ud.age between 50 and 60) = 1 and
sum(case when ud.gender = 'Female' and ud.age between 40 and 50 and ud.income between 30000 and 40000) = 1;
This gives you the user_ids that match. You can then format it however you like.
The above is quite generic. You might find that this version works faster:
select ud1.*, ud2.*
from UserDetails ud1 join
UserDetails ud2
on ud1.user_id = ud2.user_id
where ud1.gender = 'Male' and ud1.age between 50 and 60 and
ud2.gender = 'Female' and ud2.age between 40 and 50 and ud2.income between 30000 and 40000;
Which is faster depends on the size of your data and how indexes are set up.
You can join the same table twice under different names, and use this to populate all the fields.
You could do this by selecting the male person and the female person, but this will obviously get you in trouble when you need to deal with parties where both members are of the same sex. It might be better then to just pick the lowest ID and the highest ID in the database, or the youngest and oldest person, or whatever.
Query would look something like this (untested)
SELECT u.id, u.username, u.distance, u.status, p1.name, p2.name, p1.age, p2.age, p1.income, p2.income
FROM Users u
INNER JOIN UserDetails p1 ON u.id = p1.user_id AND p1.id = (SELECT MIN(id) FROM UserDetails WHERE user_id = u.id)
RIGHT JOIN UserDetails p2 ON u.status == 'married' AND u.id = p2.user_id AND p2.id = (SELECT MAX(id) FROM UserDetails WHERE user_id = u.id)
Adding in the "status == married" in the second (right) join will make sure that the second query will not show the same person twice, but will instead just return a row of nulls.
You'll probably need to do the query twice (so that each person can be searched as p1 and as p2) if one of the two spouses should be "50-60" and the other "40-50" or one should make $10.000 and the other $20.000, because you don't know in which order they'll come out.

TABLE 1 with name and surname and TABLE 2 with two columns reference to names on TABLE 1

I'm not a programmer and I read alot from this form about how to solve my question, but my search was no good
I have two tables
TABLE 1: members
id*| name | surname
-------------------
1 | Joe | Smith
2 | Mary | Sullivan
3 | Will | Stevenson
TABLE 2: messages
---------------------------------
id_message*| from | to | message
---------------------------------
1 | 2 | 1 | test
2 | 1 | 2 | re:test
3 | 3 | 1 | hi
*auto-increment fields
I wish to do a query where lists all the messages as shown below:
Mary Sullivan | Joe Smith | test
Joe Smith | Mary Sullivan | re:test
Will Stevenson | Joe Smith | hi
I'm really really really lost
Anyone can help? Thanks!
You need to join the members table 2 times with messages
select
concat(mem1.name,' ',mem1.surname) as `from_name`,
concat(mem2.name,' ',mem2.surname) as `to_name`,
m.message
from messages m
join members mem1 on mem1.id = m.`from`
join members mem2 on mem2.id = m.`to`
Try:
select from1.name+" "+from1.surname, to2.name+" "+to2.surname, message from table2
join table1 from1 on table2.`from` = table1.id
join table1 to2 on table2.`to` = table1.id
You need to write a Select with alias to refer members table 2 times:
SELECT CONCAT(M1.surname, ' ', M1.name) as FROM, CONCAT( M2.surname, ' ', M2.name) as TO FROM
members M1 INNER JOIN
messages M on M.from = M1.id
INNER JOIN messages M2 on M.to = M2.id

Join 2 tables, print data from 2nd table when joined rows occur

The case:
I have 2 tables, 'contracts' and 'members' tied with contract.id = members.cid.
Each contract has one main member and several secondary members (usually the children and spouse of the main member). The main member's details (name, address etc) are stored in table contracts whereas, extra members details are kept in table members. (bad logic, i know but this was a mess to begin with and i need time to redesign the db and website)
The desired output:
When I run a batch print of all contracts (lets say, every Friday) I need to also print a copy of the contract for each member, too but with the member's details on the contract instead of the main member.
The question:
How does this translate into a mysql query? Ok, its a left join, but how do I say "print data from table members instead of contracts for the joined rows"?
Main fields that occur in the 2 tables are name + surname, those should be enough for a draft query example.
Example tables and data:
contracts
-------------------------
id | name | surname |
-------------------------
1 | Tom | Jones |
2 | Jamie | Oliver |
members
--------------------------------
id | cid | name | surname |
--------------------------------
1 | 1 | Jack | Jones |
2 | 1 | Anne | Jones |
3 | 2 | Cathy | Wilson |
So the results I want shoudld be:
cid | name | surname |
--------------------------
1 | Tom | Jones |
1 | Jack | Jones |
1 | Anne | Jones |
2 | Jamie | Oliver |
2 | Cathy | Wilson |
If i write
SELECT c.name as name, c.surname as surname, m.name as name, m.surname as surname
FROM contracts c
join members m on c.id = m.cid
I simply end up with
name and name_1, surname and surname_1 but I want ALL names to fall under name and likewise for all other matching columns.
Hope this works :::
select c1.id, c1.name, c1.surname
from contracts c1
union
(Select m.id, m.name, m.surname
from
members m left join contracts c on (c.id = m.cid))
This is what I finally did and it worked (field names are different but the syntax is what matters):
SELECT u.id, u.onoma_u, u.name_u,
coalesce(u.programa, aa.programa) as programa,
coalesce(u.barcode, aa.barcode) as barcode,
coalesce(u.plan, aa.plan) as plan,
coalesce(u.im_exp, aa.im_exp) as im_exp,
coalesce(u.symb, aa.symb) as symb
FROM (SELECT a1.id, a1.onoma_u, a1.name_u, a1.programa, a1.barcode, a1.plan, a1.im_exp, a1.symb
FROM aitisi a1
UNION
SELECT a2.id, m.name, m.surname, NULL, NULL, NULL, NULL, NULL
FROM members m
JOIN aitisi a2 ON a2.id = m.symbid) u
JOIN aitisi aa ON aa.id = u.id;
I used aliases and NULLS as dummy fields to fill in the blanks.