SQL JOIN return only the first match - sql

I think this is a basic question, but I couldn’t figure it out. I am new to this so please bear with me.
I am analyzing players data from the FIFA game, and I want to get a table with the highest rating of each individual player and the earliest age when that happened.
This is an example of the data:
id
name
position
rating
age
1
James
RW
70
20
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
3
Miles
CM
74
28
This is what the query should return:
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
3
Miles
CM
75
27
I thought I could first get the highest overall for each player, and then do a JOIN to get the age, but that gives the other years a player had the same highest rating.
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
Thank you,

One approach uses ROW_NUMBER with QUALIFY:
SELECT *
FROM yourTable
WHERE true
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY rating DESC, age) = 1;

Try this one (could be a bit faster):
with mytable as (
select 1 as id, "James" as name, "RW" as position, 70 as rating, 20 as age union all
select 1, "James", "RW", 71, 21 union all
select 2, "Frank", "CB", 73, 23 union all
select 2, "Frank", "CB", 73, 24 union all
select 3, "Miles", "CM", 75, 27 union all
select 3, "Miles", "CM", 74, 28
)
select array_agg(t order by rating desc, age asc limit 1)[OFFSET(0)].*,
from mytable as t
group by t.id

Try this one too if you want. I think it's what you need.
select p1.id,
p1.name,
p1.pos,
max(p1.rating),
p1.age
from players p1
join (select name, min(age) min_age
from players
group by 1) p2 on p1.name = p2.name and p1.age = p2.min_age
group by p1.id, p1.name, p1.pos, p1.age

Related

Access SQL Query Top 1 of Group

I am trying to write a query that selects the Top record in each Group of Data.
eg Below
Division
Team
Points
1
Liverpool
90
1
Manchester
88
2
Leeds
94
2
Arsenal
77
3
Bolton
66
3
Spurs
72
3
Derby
33
I want my query to return the team with highest number of points in each division:
Division
Team
Points
1
Liverpool
90
2
Leeds
94
3
Spurs
72
I thought this should be easy.
Any ideas?
Thanks
In MS Access, you can use:
select t.*
from t
where t.points = (select max(t2.points)
from t t2
where t2.division = t.division
);
If there are ties, then this returns all matching teams. If you want only one team even when there are ties:
select t.*
from t
where t.team = (select t2.team
from t t2
where t2.division = t.division
order by t2.points desc, t2.team
);

HIVE Get male and female count who opted for any course

I have two tables, students and training. Student and Training tables are as below.
Student
ID name age sex salary
1213 lavanya 18 Female 8000
1208 reshma 19 Female 14000
1207 bhavya 20 Female 15000
1212 Arshad 28 Male 20000
1209 kranthi 22 Male 22000
1210 Satish 24 Male 25000
1211 Krishna 25 Male 26000
1203 khaleel 34 Male 30000
1204 prasant 30 Male 31000
1206 laxmi 25 Female 35000
1205 kiran 20 Male 40000
1201 gopal 45 Male 50000
1202 manisha 40 Female 51000
Training
1 1201 csharp
2 1205 c
3 1201 c
4 1202 java
5 1205 java
6 1203 shell
7 1204 hadoop
8 1201 hadoop
Now I want count of males and females who have joined any course.
I tried below query-
hive> select s.sex, count(*) from student join training t on s.id=t.sid group by s.sex;
But this query is giving output as Female 2 Male 4
Though expected outcome should be Female 1 Male 2
Please note this is a sample and short form of data being used.
This looks like your query, but - returns the result you mentioned (1 female, 2 male). If possible, post your own SQL*Plus copy/paste session (take my example) so that we'd see what you exactly did).
SQL> with student (id, name, sex) as
2 (select 1, 'alex', 'm' from dual union
3 select 2, 'rita', 'f' from dual union
4 select 3, 'max', 'm' from dual union
5 select 4, 'steve', 'm' from dual
6 ),
7 training (id, sid, course) as
8 (select 1, 2, 'java' from dual union
9 select 2, 3, 'c' from dual union
10 select 3, 1, 'java' from dual
11 )
12 select s.sex, count(*)
13 from student s join training t on t.sid = s.id
14 group by s.sex;
S COUNT(*)
- ----------
m 2
f 1
I try in MySQL and in Oracle, and this query is OK.
SELECT S.sex, count(*)
FROM student s
INNER JOIN training T on S.id = T.sid
GROUP BY S.sex;
RESULT, female = 1, male = 2
If the only thing you want is a simple count by gender, why not use
select sex, count(*)
from student
group by sex
order by sex
Use exists:
select s.sex, count(*)
from students s
where exists (select 1 from training t where t.sid = s.id);
The problem with join is that it counts each student based on the number of trainings they are in.
Here i had written a code taking your data:-
SELECT
final.ct_sex as sex,count(*) as num
FROM
(SELECT tb.sex as ct_sex FROM newschema.mytable AS tb JOIN (SELECT tr.ID,GROUP_CONCAT(tr.skill) as skills FROM newschema.train AS tr GROUP BY tr.ID) AS tp ON tb.ID = tp.ID) as final
group by
final.ct_sex
Not sure why join fails here, Below subquery is giving correct output though.
select sex, count(*) from salary where salary.id in (select sid from training) group by salary.sex;

SQL Subquerys and RANK()

I'm using below for a tournament system. The table contains registrered lengths for all teams. The result will be a scoreboard, summing up all teams length in a totalScore.
I'm trying to get the RANK() function into my SQL but I'm stuck right now. I want to get the current teams rank score out from my DB. Anyone got any ideas? I'm using MariaDB.
select team, sum(length) as totalScore
from
(SELECT t.*,
#num_in_group:=case when #team!=team then #num_in_group:=0 else #num_in_group:=#num_in_group+1 end as num_in_group,
#team:=team as t
FROM reg_catches t, (select #team:=-1, #num_in_group:=0) init
ORDER BY team asc, length desc) sub
WHERE sub.num_in_group<=4
GROUP BY team
ORDER BY totalScore DESC;
Table
team length
-----------
26 70
25 70
25 95
25 98
25 100
25 100
25 100
25 122
Current output
team totalScore
-- --
25 520
26 70
Wanted output
rank team totalScore
-- -- --
1 25 520
2 26 70
SET #row = 0;
SELECT #row:=#row + 1 rank, a.team, a.total_score
FROM(SELECT team, sum(r.length) as total_score FROM reg_catches r GROUP BY
r.team) a;
Try the above
Got this far now with above help from Dickson, problem now is that it seems that the rank is based on team ID instead of totalScore :O
SET #row = 0;
SELECT #row:=#row + 1 rank, team, sum(length) as totalScore
from
(SELECT t.*,
#num_in_group:=case when #team!=team then #num_in_group:=0 else #num_in_group:=#num_in_group+1 end as num_in_group,
#team:=team as t
FROM reg_catches t, (select #team:=-1, #num_in_group:=0) init
ORDER BY team asc, length desc) sub
WHERE sub.num_in_group<=4 and competition = "#COMPID" and disqualified = 0
GROUP BY team
ORDER BY totalScore DESC
Current output
rank team totalScore
1 28381 479
58 28468 439
20 28412 436
25 28419 432
14 28404 427
5 28388 421
Wanted would be
rank team totalScore
1 28381 479
2 28468 439
3 28412 436
4 28419 432
5 28404 427
6 28388 421
SQL Fiddle: http://sqlfiddle.com/#!9/107d98/2/1

How to sum in sql with a DISTINCT clause

In the following example SQL Fiddle
How should I proceed to obtain the cumulative price for each 'Phone' instead of obtaining the last value?
In the example given below, I would need the following table to be produced:
Phone Price Purchases
50 35 3
51 50 2
52 99 3
55 21 2
53 16 2
54 21 1
56 16 1
58 22 1
57 10 2
This is to be done in SQL-Server 2012
Thanks in advance.
You should be able to use the following:
select c1.phone,
c2.TotalPrice,
c1.purchases
from supportContacts c1
inner join
(
select
max(Fecha) maxFecha,
sum(price) TotalPrice,
phone
from supportContacts
group by phone
) c2
on c1.phone = c2.phone
and c1.Fecha = c2.maxFecha
order by c1.phone;
See SQL Fiddle with Demo.
The subquery gets the Total sum for each phone along with the the max fecha associated with the phone. You then use this and join back to your table on both the phone and the fecha to get the result.
I don't have a SQL Server 2012 handy, but give this a shot:
select
phone,
purchases,
price,
sum(price) over (partition by phone order by phone, price) as running_sum_purchases
FROM
supportContacts
Isn't it just...
SELECT Phone, Sum(Price), Count(Purchases)
FROM supportContacts
GROUP BY Phone
ORDER BY 1
.. or have I missed something?
http://sqlfiddle.com/#!6/7b36f/41
50 35 3
51 50 4
52 99 3
53 16 2
54 21 2
55 21 1
56 16 1
57 10 1
58 22 2
If you need more details per phone, you can add a subquery :
SELECT
Phone,
Sum(Price) as Total,
Count(Purchases) as Purchase_Count,
(SELECT TOP 1 Price
FROM supportContacts sc2
WHERE sc2.phone=sc1.phone
ORDER BY fecha DESC
) as Most_Recent
FROM supportContacts sc1
GROUP BY Phone
ORDER BY Phone
or, for the actual requirement which I've finally worked out :)
SELECT
Phone,
Sum(Price) as Total,
Count(Purchases) as Purchase_Count,
(SELECT Purchases
FROM supportContacts sc2
WHERE sc2.phone=sc1.phone
AND sc2.Fecha=
(SELECT Max(Fecha)
FROM supportContacts sc3
WHERE sc3.phone=sc1.phone
)
) as Last_Purchase
FROM supportContacts sc1
GROUP BY Phone
ORDER BY Phone
.. which is starting to get quite unwieldy, there's probably an optimisation possible, but I'm losing the will to play... LOL
But thanks for the cerebral exercise of trying to do it this way :)
EDIT
I would probably have done it like this, if it had been me...
http://sqlfiddle.com/#!6/7b36f/98
With PhoneGroup as
( SELECT
Phone,
Sum(Price) as Total_Price,
Max(Fecha) as Last_Fecha
FROM supportContacts
GROUP BY Phone
)
SELECT
Phone, Total_Price,
(SELECT Purchases
FROM supportContacts sc2
WHERE sc2.phone=PhoneGroup.phone
AND sc2.Fecha=PhoneGroup.Last_Fecha
) as Last_Purchase
FROM PhoneGroup
ORDER BY Phone

sql query to order the data

I want to order the data in column for a table in one order that is i am having a table Person having age like
age
12
14
13
14
45
12
45
23
12
23
12
I want to group all the similar ages one after other.How to do this?I have tried using group by
select age from person group by age.This is not working for me.
SELECT age FROM Person ORDER BY age
Try this:
SELECT * FROM Person ORDER BY age
In MySQL, you can use GROUP BY without aggregating columns but in oracle you can't. Try it using DISTINCT so it will only select unique values.
SELECT DISTINCT age
FROM Person
Order by age ASC
I thought you want to join tables, in order to do that you have the following alternatives:
1) simple join with distinct/unique
select distinct person.name, age.age
from person, age
Where Person.Age = Age.Age
order by age.age
Result:
person_5 12
person_3 14
person_1 23
person_4 23
person_2 45
2) right outer join
Select Distinct Person.Name, Age.Age
from person right outer join age
on Person.Age = Age.Age
order by age.age
Result:
person_5 12
null 13
person_3 14
person_1 23
person_4 23
person_2 45
3) left outer join
Select Distinct Person.Name, Age.Age
from person left outer join age
On Person.Age = Age.Age
order by age.age
Result:
person_5 12
person_3 14
person_1 23
person_4 23
person_2 45
The source tables:
Person table(person and age column):
person_1 23
person_2 45
person_3 14
person_4 23
person_5 12
Age table (age column only):
12
14
13
14
45
12
45
23
12
23
12