mysql select in another select group: how many people in downline? - mysql

Hello i've a table similar to this one:
id sponsor name
------------------------
1 0 Sasha
2 1 John
3 1 Walter
4 3 Ashley
5 1 Mark
6 4 Alexa
7 3 Robert
8 3 Frank
9 4 Marika
10 5 Philip
11 9 Elizabeth
when i choose an ID (call it MYCHOICE) i want know all the name of people who has sponsor like MYCHOICE... is simply:
select * from tablename where sponsor=MYCHOICE
but... here is the problem... i would know how many people there is in the downline of this results... so... how many records there are with sponsor like each id.
if i choose id 1 result should be
id name downline
----------------------
2 John 0 (noone with sponsor=2)
3 Walter 3 (3 with sponsor=3: ashley, robert, frank)
5 Mark 1 (1 with sponsor=5: philip)
if i choose id 4 result should be
id name downline
----------------------
6 Alexa 0
9 Marika 1 (1 with sponsor=9: Elizabeth)
i try this "bad solution" if mychoice is 1
select sponsor,count(*) as downline from tablename where sponsor in
(select id from tablename where sponsor=1) group by sponsor order by
downline desc
result of this query is
sponsor downline
---------------------
3 3
5 1
there are 2 problems:
- names are not rights and is not that i want
- the count 0 "2|John|0" in the example dont appears
thank u for advice and help, sorry for english,
N.

SELECT child.id,
child.name,
COUNT(grandchild.sponsor) downline
FROM TableName child
INNER JOIN TableName parent
ON child.sponsor = parent.id AND
parent.id = ? -- << user choice
LEFT JOIN TableName grandchild
ON child.id = grandchild.sponsor
GROUP BY child.id, child.name
SQLFiddle Demo
As you can see, the table is joined to itself twice. The first join that uses INNER JOIN gets the records associated with the Sponsor which is your user_choice. The second join which uses LEFT JOIN gets all the records associated with records from your user_choice.

Related

How can i count all rows without miss them?

SELECT t1.s_name, count(*) FROM tvSeries AS t1, subTitles AS t2, votes as t3
WHERE
t1.s_id IN (SELECT t2.s_id WHERE sLang='English') AND
t1.s_id IN (SELECT t3.s_id WHERE pts=5) AND
t1.s_id IN (SELECT t3.s_id WHERE uid='britney');
My tvSeries table is like:
s_id s_cat s_name
1 comedy a
2 comedy b
3 drama c
4 comedy d
5 drama e
My subTitles table is like:
s_id sLang
1 English
1 Spanish
2 French
2 English
3 English
1 French
4 German
4 English
5 English
My votes table is like:
s_id uid pts
1 john 4
1 mia 3
1 britney 5
2 rock 5
3 anna 1
3 britney 5
4 megan 3
5 britney 5
I want to select total number of tvSeries and name of tvSeries in this conditions;
which tvSeries gets 5 star from user 'britney' with English subtitles.
When I use my code, I get only one row with number of tvSeries but i want to see many rows with total value. Can anyone help me?
You can do this with simple JOINs (see this answer for an explanation of JOIN vs ,), and then your conditionals are clean and easy to understand.
SELECT
t.s_id,
t.s_name
FROM
tvSeries t
JOIN subTitles s ON s.s_id = t.s_id
JOIN votes v ON v.s_id = t.s_id
WHERE
s.sLang = 'English'
AND v.pts = 5
AND v.uid = 'britney';
If you want just the count of shows instead, you can do:
SELECT
COUNT(*) as count
FROM
...
You can't easily get both the names of the series as well as the count in the same row (because COUNT is an aggregating function), but if you need it you can do:
SELECT
GROUP_CONCAT(t.s_name) as series_names,
COUNT(*) as count
FROM
...
though that returns a single row with concatenated series names (a,c,e) rather than rows which are able to be iterated over.
See http://sqlfiddle.com/#!9/2c252c/13 for a working example.

Query to find all people who have had a child with more than one person

I need to find the list of all people who have had a child with more than one person. I am using one table that has the person name, person ID. The person's ID also serves as their mother_ID and father_ID.
ID NAME Father ID Mother ID
1 Paul
2 Debbie
3 Jessie
4 Pam 1 3
5 Sue 1 3
6 Trish 1 3
7 Sarah 1 2
9 John
10 johnny 9 4
11 Ben 9 4
In the example above, I want to find Paul who has four children with two different people, Debbie and Jessie.
Try this:
select * from
your_table a where
(select count(distinct father_id, mother_id)
from your_table b where b.father_id=a.id or b.mother_id=a.id)>1;
See it run on SQL Fiddle.
You could use COUNT(DISTINCT col) > 1:
SELECT *
FROM table
WHERE Id IN (
SELECT Father_Id
FROM table
GROUP BY Father_Id
HAVING COUNT(DISTINCT Mother_id) > 1
UNION ALL
SELECT Mother_Id
FROM table
GROUP BY Mother_Id
HAVING COUNT(DISTINCT Father_Id) > 1
);
DBFiddle Demo

Fetch rows which belonging to the parent category which has more than two rows

I have some combination of company and members
Member Table
id company_id companymember
1 1 john
2 1 Tam
3 2 haya
4 1 lee
5 3 kih
6 3 wild
7 3 cream
8 3 earth
What I want to pick up is
the 3 member names which belonging to the company which has more than two members
What I want is like this
company_id 2 has only 1 member, 3rd row is not selected
company_id 3 has 4 members, so 8th row is not selected
My Goal
1 1 john
2 1 Tam
4 1 lee
5 3 kih
6 3 wild
7 3 cream
I could make it , pick up company_ids first and
loop each id by script and fetch.
However in this way, it exec sql many times.
Is there any good way to do this on MySql by one sentence SQL??
Try this
select id,company_id,companyMember
from (Select id
,company_id
,companyMember
,Row_Number() OVER(PARTITION BY company_id ORDER By company_id) AS TotalCount
from MemberTable
) as Table1
where TotalCount <=3 and Company_id in(
Select Company_id
from MemberTable
group by Company_id
having COUNT(Company_id) >=3
)
order by id

Group by 2 columns with 2 joins and return all rows with totals

I have 3 tables which I need to query where I need to group by 2 columns and also join the tables but still return all results.
Users
ID User_name Category Reason Change_date
1 John 1 2 2016-01-05
2 James 3 1 2015-10-02
3 Peter 1 4 2016-01-04
4 Tony 1 4 2016-01-15
5 Fred 1 4 2016-02-25
6 Rick 3 2 2016-04-19
7 Sonia 2 1 2016-10-14
8 Michelle 2 2 2015-11-09
9 Phillip 3 3 2016-03-01
10 Simon 3 3 2016-03-07
Category
ID Category_name
1 User
2 Super user
3 Admin
Reason
ID Reason_name
1 Promotion
2 Upgrade
3 Sponsor
4 Normal
I did some searching and found https://stackoverflow.com/a/28158276/1278201 and modified my query to try and use it:
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name
from users as u1
JOIN (SELECT id from users where users.change_date BETWEEN '2016-01-01'
AND '2016-11-06' group by users.category, users.reason) AS u2
ON u1.id = u2.id
left join reason on u1.reason=category.id
left join category on u1.category=category.id
The results being returned are only using the group by - I should have 8 rows returned but I am only getting 5 which is one for each occurrence of each reason within each category.
My expected outcome is:
category_name reason_name user_id user_name
User Upgrade 1 John
"Upgrade" count 1
Normal 3 Peter
4 Tony
5 Fred
"Normal" count 3
"User" count 4
Super user Promotion 7 Sonia
"Promotion" count 1
"Super user" count 1
Admin Upgrade 6 Rick
"Upgrade" count 1
Sponsor 9 Phillip
10 Simon
"Sponsor" count 2
"Admin" count 3
How can I get all 8 rows returned as well as being able to get counts for each category_name and reason_name?
For what you are looking for in the expected output, this might be what you looking for:
SELECT
Category_name, reason_name, users.ID,User_name
FROM
Users
inner join Category on Category.ID=Users.Category
inner join Reason on Reason.ID=Users.Reason
where users.change_date BETWEEN '2016-01-01' AND '2016-11-06'
SQLFiddle
You shouldn't use GROUP BY in the subquery, because then it only returns one user ID from each group.
In fact, you don't need the subquery at all. You can just use a WHERE clause to select users that meet the change_date criteria.
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name
from users as u1
left join reason on u1.reason=category.id
left join category on u1.category=category.id
where u1.change_date BETWEEN '2016-01-01' AND '2016-11-06'
To get subtotals of the groupings by category and reason, you can use GROUP BY and WITH ROLLUP.
SELECT category_name, reasons.reason_name, u1.id as user_id, user_name, COUNT(*) AS total
from users as u1
left join reason on u1.reason=category.id
left join category on u1.category=category.id
where u1.change_date BETWEEN '2016-01-01' AND '2016-11-06'
GROUP BY category_name, reason_name, user_id WITH ROLLUP
In the script that displays the results, the totals are in the rows where user_id is NULL. The category totals also have reason IS NULL. So you can display these rows appropriately in the script that displays the results. If you really need to do it all in MySQL, you can put the above query in a subquery, and the containing query can test for user_id IS NULL and reason_name IS NULL.

MySQL Join Multiple (More than 2) Tables with Conditions

Assume I have 4 tables:
Table 1: Task
ID Task Schedule
1 Cut Grass Mon
2 Sweep Floor Fri
3 Wash Dishes Fri
Table 2: Assigned
ID TaskID (FK) PersonID (FK)
1 1 1
2 1 2
3 2 3
4 3 2
Table 3: Person
ID Name
1 Tom
2 Dick
3 Harry
Table 4: Mobile
ID PersonID (FK) CountryCode MobileNumber
1 1 1 555-555-5555
2 2 44 555-555-1234
3 3 81 555-555-5678
4 3 81 555-555-0000
I'm trying to display the
Task on a certain day
Name of person assigned to task
Phone numbers of said person
I think it should be something like the following, but I'm not sure how to set up the conditions so that the results are limited correctly:
SELECT T.ID, T.Task, P.Name, M.MobileNumber
FROM Task AS T
LEFT JOIN Assigned AS A
ON T.ID = A.TaskID
LEFT JOIN Person AS P
ON A.PersonID = P.ID
LEFT JOIN Mobile AS M
ON M.PersonID = P.ID
WHERE T.Schedule = Fri
My goal is to fetch the following information (it will be displayed differently):
Tasks Name MobileNumber
Sweep Floor, Wash Dishes Dick, Harry 44-555-555-1234, 81-555-555-5678, 81-555-555-0000
Of course, if JOIN is the wrong way to do this, please say so.
It's unclear what you want to do with duplicate data in this case, but you should be looking at using inner joins instead of outer joins, and using something like group_concat() to combine the phone numbers.