SQL query to get info from different tables - sql

Need a help with sql query.
I have 2 tables.
Matches.
first_referee_arbitr_id
second_referee_arbitr_id
home_team
guest_team
date
Arbitrs.
id
name
surname
first_referee_arbitr_id and second_referee_arbitr_id are from Arbitrs table(id).
As the result I need to count how much each referee has been included in matches:
referee_first_count | referee_second_count | Arbitr Surname | Arbitr Name
My query now:
SELECT T1.referee_first_count, T2.referee_second_count, T1.surname, T1.name
FROM (
select matches.first_referee_arbitr_id, q.surname, q.name, count(*) AS referee_first_count
FROM matches
JOIN (
SELECT name, surname, id
FROM arbitrs
) as q ON matches.first_referee_arbitr_id=q.id
GROUP BY matches.first_referee_arbitr_id, q.name, q.surname
ORDER BY referee_first_count DESC
) T1 FULL OUTER JOIN
(
select matches.second_referee_arbitr_id, arbitr.surname, arbitr.name, count(*) AS referee_second_count
FROM matches
JOIN (
SELECT name, surname, id
FROM arbitrs
) as arbitr ON matches.second_referee_arbitr_id=arbitr.id
GROUP BY matches.second_referee_arbitr_id, arbitr.name, arbitr.surname
ORDER BY referee_second_count DESC
) T2
ON (
(T1.name = T2.name) AND (T1.surname = T2.surname)
)
Example
Arbitrs:
id | Name | Surname
1 John Rambler
2 Steve Crystler
3 Tom Ferguson
Matches:
first_referee_arbitr_id| second_referee_arbitr_id| home_team | guest_team | date
1 Chelsea Everton 22.06.2020
2 1 Liverpool Lester 28.06.2020
3 Dinamo K Dinamo M 06.07.2020
1 2 Juventus Dinamo K 10.10.2020
3 Dinamo K Chelsea 20.20.2020
Result:
referee_first_count | referee_second_count | surname | name
2 1 Rambler John
1 1 Crystler Steve
2 0 Ferguson Tom
My result now with query above:
referee_first_count | referee_second_count | surname | name
2 1 Rambler John
1 1 Crystler Steve
2 NULL NULL NULL

First aggregate the matches table (twice) and left join this to the Arbitrs table:
SELECT a.name , a.Surname , ISNULL(fir.first_count,0) , ISNULL( sec.sec_count,0)
FROM Arbitrs a
LEFT JOIN (
SELECT first_referee_arbitr_id,COUNT(*) as first_count
FROM Matches
GROUP BY first_referee_arbitr_id
) fir
ON fir.first_referee_arbitr_id = a.id
LEFT JOIN (
SELECT second_referee_arbitr_id,COUNT(*) as sec_count
FROM Matches
GROUP BY second_referee_arbitr_id
) sec
ON sec.second_referee_arbitr_id = a.id

SELECT
a.name
, a.surname
, COUNT(CASE WHEN m1.id IS NOT NULL THEN 1 end) referee_first_count
, COUNT(CASE WHEN m2.id IS NOT NULL THEN 1 end) referee_second_count
FROM
Arbitrs a
LEFT JOIN macthes m1
ON a.id = m.first_referee_arbitr_id
LEFT JOIN macthes m2
ON a2.id = m.second_referee_arbitr_id
GROUP BY
a.name
, a.surname
-- if you want to show only those with refrence
HAVING referee_first_count > 0 or referee_second_count > 0

Related

Not able to generate SQL Join query for Postgres

I have a table structure like this and I am using Postgres
ContactPhoneRelation
id
ContactId
PhoneId
1
123
999
2
123
998
I have another table GroupTable
id
groupId
ContactId
PhoneId
1
1
123
999
2
2
123
999
3
2
123
998
I am trying to fetch the data from ContactPhoneRelation which does not exist in groupId 1 and ContactId is 123, So I want to query such that where groupId is 1 and ContactId is 123 and ContactId phoneId both does not exists in groupId 1
So in return, it should give me this result
id
contactId
PhoneId
2
123
998
If I query for groupId 2, It should give me 0 rows in return.
I tried this query but it gave me the opposite data.
select * from ContactPhoneRelation cp
left join GroupTable gt on gt.ContactId = cp.ContactId
where cp.contactId = '123' and gt.groupId = 1
In all honesty, I don't understand what you are trying to achive. But maybe this is because of language issues.
For better understanding I added an example on db<>fiddle: Link
Edit (29.09.2021; 16:49):
SELECT
c.*
FROM
(
SELECT
b.groupID
,a.ContactID
,a.PhoneID
FROM
(SELECT DISTINCT
ContactId
,PhoneID
FROM
ContactPhoneRelation
) a
FULL JOIN
(SELECT DISTINCT
groupID
FROM
GroupTable
) b ON (1=1)
ORDER BY groupID, ContactID, phoneID
) c
LEFT OUTER JOIN GroupTable d ON (
c.groupID = d.groupID
AND c.ContactID = d.ContactID
AND c.PhoneID = d.PhoneID
)
WHERE
d.groupID IS NULL

SQL: Find country name of the team having the most players who have never scored a goal

I have the following tables:
create table Players (
id integer,
name varchar(50) not null,
birthday date,
memberOf integer not null,
position varchar(20).
primary key (id),
foreign key (memberOf) references Teams(id)
);
create table Goals (
id integer,
scoredIn integer not null,
scoredBy integer not null,
timeScored integer not null,
rating varchar(20),
primary key (id),
foreign key (scoredIn) references Matches(id),
foreign key (scoredBy) references Players(id)
);
create table Teams (
id integer,
country varchar(50) not null,
primary key (id)
);
I have the following data in the above tables:
PLAYERS:
id | name | birthday | memberof | position
7 Mina 1997-01-20 1 Captain
9 John 1997-09-01 1 Quarterback
2 Minnie 1995-10-13 3 Goalkeeper
13 Lisa 1997-03-27 4 Captain
12 Rina 1995-01-03 2 Fullback
11 Jasper 2002-09-22 1 Halfback
17 Rose 1997-02-11 1 Goalkeeper
22 Parvin 1993-03-09 3 Goalkeeper
25 Nasom 1996-12-29 3 Fullback
GOALS:
id | scoredin | scoredby | timescored | rating
1 10 7 60 amazing
2 10 7 30 okay
3 10 7 90 amazing
4 20 9 119 nice
5 20 9 80 amazing
6 20 9 75 amazing
7 30 2 30 nice
8 30 2 90 amazing
9 40 13 110 amazing
TEAMS:
id | country
1 Australia
2 Malaysia
3 Japan
4 Thailand
I am trying to output the country name of the team which has the most players who have never scored a goal. The output should be:
Country | Players
Australia 2
Japan 2
I have the following view, which gives the count of players who have never scored a goal for each country:
create or replace view zerogoals as
select t.country, count(*)
from (
select distinct p.id, p.name, p.memberof, g.scoredby
from players p
full outer join goals g
on p.id = g.scoredby where scoredby is null
) s
inner join teams t on t.id = s.memberof group by t.country;
The above query gives me the following output:
country | count
Australia 2
Japan 2
Malaysia 1
I tried using the max function to get the desired output:
select country, max(count)
from zerogoals
group by country;
However I get the following output:
country | max
Australia 2
Japan 2
Malaysia 1
I am not sure how to get the tuples in the view zerogoals with the maximum value for the attribute count. Any insights are appreciated.
You can use a CTE:
with cte as (
select
t.id, t.country, count(*) players
from teams t inner join (
select * from players
where id not in (select scoredby from goals)
) p on p.memberOf = t.id
group by t.id, t.country
)
select country, players
from cte
where players = (select max(players) from cte)
order by country
See the demo.
Results:
country | players
Australia | 2
Japan | 2
You could try using a inner join between the player, team and the list of not in goals ordered by count and limit to 1
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) ) t1 on t1.id = p.id
group by t.name
order by count(*) desc
limit 1
if you want all the max then
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) t1 on t1.id = p.id
group by t.name
having count(*) = (
select t.name , count(*)
from player p
INNER JOIN team t ON t.id = p.memberof
inner join (
select p.id
from PLAYERS p
where p.id NOT IN (
select scoredby
from GOALS
) t1 on t1.id = p.id
group by t.name
order by count(*)
limit 1
)
To get the number of players per country with no goal, you can use:
select t.name, count(*) as num_players_no_goal
from team.t join
player p
on t.id = p.memberof
where not exists (select 1
from goals g
where g.scoredby = p.id
)
group by t.name;
To limit this to just the maximum number, use window functions:
select name, num_players_no_goal
from (select t.name, count(*) as num_players_no_goal,
rank() over (order by count(*) desc) as seqnum
from team.t join
player p
on t.id = p.memberof
where not exists (select 1
from goals g
where g.scoredby = p.id
)
group by t.name
) t
where seqnum = 1;
One slight caveat is that this returns no teams if all players on all teams have scored goals. It is easily modified for that situation, but I'm guessing that you would rather return zero teams than all teams if that were the case.

Query to show one column multiplied

I have the following 3 tables;
Table_Names:
user_id Name
------------------
1 Mark
2 Tom
3 Ana
Table_Language:
language_id Language
-----------------------
1 English
2 German
Table_Name_Lang
id user_id language_id
---------------------------
1 1 1
2 1 2
3 2 1
4 3 2
How can I create a query to show the expected results like those below?
Name Expr_1_Eng Expr_1_Ger
---------------------------------
Mark English German
Tom English
Ana German
Thanks Tok
I would do:
select n.name,
max(case when l.language = 'English' then l.language end) as has_English,
max(case when l.language = 'German' then l.language end) as has_German
from names n join
name_lang nl
on nl.user_id = n.user_id join
lang l
on nl.language_id = l.language_id
group by n.name
You can try to use JOIN with condition aggregate function
SELECT Name,
MAX(CASE WHEN tnl.language_id = 1 then tl.Language end),
MAX(CASE WHEN tnl.language_id = 2 then tl.Language end)
FROM
Table_Name_Lang tnl
JOIN Table_Names tn on tnl.language_id = tn.language_id
JOIN Table_Language tl on tl.user_id = tnl.user_id
GROUP BY Name
I think you should use pivot:
select n.name,[0] as language_one,[1] as language_two,[2],[3] from
(select n.name,tl.language
tablename n
left join Table_Name_Lang tnl on n.userid=tnl.userid
left join table_language tl on tl.id=tnl.id
group by n.name,tl.language
)T
pivot
(
language
for name in [0],[1],[2],[3]
)AS PivotTable;

join two SQL rows in a single one

I have three tables in Postgresql, for a biological classification system.
table lang (languages)
id name
1 português
2 english
-------------------------------
table taxon (biological groups)
id name
...
101 Mammalia
-------------------------------
table pop (popular names)
id tax lang pop
...
94 101 1 mamíferos
95 101 2 mammals
I want to get
id name namePT nameEN
101 Mammalia mamíferos mammals
but my join is giving me
id name pop
101 Mammalia mamíferos
101 Mammalia mammals
select t.id,name,pop from taxon t
left join pop p on p.tax = t.id
where t.id = 101
How can I get the desired result in a single row?
If you are happy to change query every time you add a new language then this query will do the trick:
select t.id,name,pe.pop as eng_pop, pp.pop as port_pop
from taxon t
left join pop pe on pe.tax = t.id and pe.lang = 1
left join pop pp on pp.tax = t.id and pp.lang = 2
where t.id = 101
You could use this
SELECT t.id, t.name,
MAX(CASE WHEN p.lang = 1 THEN p.pop END) AS namePT,
MAX(CASE WHEN p.lang = 2 THEN p.pop END) AS nameEN
FROM taxon t
LEFT JOIN pop p
ON p.tax = t.id
GROUP BY t.id, t.name;
Here's how I got the results:
with base as (
select t.id, t.name,
case when lang = 1 then 'mamiferos' else null end as namePT,
case when lang = 2 then 'mamals' else null end as nameEN
from taxon t
left join pop p on t.id = p.tax
group by 1,2,3, p.lang
)
select
distinct id,
name,
coalesce(namept,'mamiferos',null) as namept,
coalesce(nameen,'mamals',null) as nameen
from base
where id = 101
group by id, name, namept, nameen;
id | name | namept | nameen
-----+----------+-----------+--------
101 | Mammalia | mamiferos | mamals
(1 row)

Select all columns from two tables grouping by all columns in table1 and specific column in table2

My table structure is like below
TblMemberInfo | TblCarInfo
MemberID Name | Id MemberId CarNumber
1 Sandeep | 1 2 1234
2 Vishal | 2 1 1111
3 John | 3 4 2458
4 Kevin | 4 2 1296
5 Devid | 5 4 7878
| 6 3 4859
I need to query for select all from TblMemberInfo,TblCarInfo where Count(MemberId)=1
MemberId Name CarNumber
1 Sandeep 1111
3 John 4859
Here is one method:
select mi.MemberID, mi.Name, min(CarNumber) as CarNumber
from TblMemberInfo mi join
TblCarInfo ci
on mi.MemberID = ci.MemberID
group by mi.MemberID, mi.Name
having count(*) = 1;
This works, because with only one row in the group, the min() returns the right value.
And alternative approach uses not exists:
select mi.MemberID, mi.Name, ci.CarNumber
from TblMemberInfo mi join
TblCarInfo ci
on mi.MemberID = ci.MemberID
where not exists (select 1
from TblCarInfo ci2
where ci2.MemberID = ci.MemberID and ci2.id <> ci.id
);
A couple more options!
select mi.MemberId, mi.Name, ci.CarNumber
from TblMemberInfo mi
join TblCarInfo ci on
mi.MemberId = ci.MemberId
group by mi.MemberId, mi.Name, ci.CarNumber
having min(ci.Id) = max(ci.Id)
Using a subquery to retrieve the single MemberId's is a good idea if you have a lot of other columns you need to bring in as well
select mi.MemberId, mi.Name, ci.CarNumber
from TblMemberInfo mi
join TblCarInfo ci on
mi.MemberId = ci.MemberId
where mi.MemberId in
(
select MemberId
from TblCarInfo
group by MemberId
having count(*) = 1
)
What would you do given that task? Probably: Find unique TblCarInfo member entries first and then look up the member name. So tell the DBMS to do exactly that:
select m.memberid, m.name, c.carnumber
from
(
select memberid, min(carnumber) as carnumber
from tblcarinfo
group by memberid
having count(*) = 1
) c
join tblmemberinfo m on m.memberid = c.memberid;
Or the same approach, but with a subquery in the select clause instead of a join:
select
c.memberid,
(select m.name from tblmemberinfo m where m.memberid = c.memberid) as name,
c.carnumber
from
(
select memberid, min(carnumber) as carnumber
from tblcarinfo
group by memberid
having count(*) = 1
) c;