Use STRING_AGG to get Values from 3 different Tables - sql

I am trying to get comma-separated values from the following 3 tables:
Teams: Id
Players: Id, Name
TeamsPlayers: Id, TeamId, PlayerId
What I am trying to get is a result like this:
TeamId
PlayerNames
1
Ronaldo,Rivaldo,Ronaldinho,Dida
2
Riquelme,Messi,Aguero,DiMaria
sql
SELECT STRING_AGG(Name, ',')
FROM (
SELECT tp.TeamId, p.Name
FROM Players p
JOIN TeamPlayers tp ON p.Id = tp.PlayerId
GROUP BY tp.TeamId, p.Name
)

Expanding on Larnu's comment.
Asssuming your initial query has the proper elements
SELECT tp.TeamId,
,Names = STRING_AGG(p.Name, ',')
FROM Players p
JOIN TeamPlayers tp ON p.Id = tp.PlayerId
GROUP BY tp.TeamId

Related

How do I use MAX and Count with two table

I have a query that needs to count the field Points. Then returns the highest value. This query does that fine however I now want to link another table 'Team(PlayerID) with Player(PlayerID), So it shows the player team details etc. I attempted to do that normally on how you would join table but keep getting errors. I also do not want to use the order by desc - First row only. (Oracle)
Query:
SELECT PlayerID, COUNT(Points)
SELECT t.*, p.* FROM
team t INNER JOIN
(SELECT PlayerID, COUNT(Points)
FROM Player
WHERE Points = 1
group by PlayerID
HAVING COUNT(Points) = (SELECT MAX(count(Points))
from Player
WHERE Points = 1
group by PlayerID)
) p
ON t.PlayerID = p.PlayerID
....
HAVING COUNT(Points) = (SELECT MAX(sub.cp)
from (SELECT count(Points) as cp
from Player
WHERE Points = 1
group by PlayerID) sub
)
SELECT A.PlayerID, a.TotalPoints, b.[stuff]
FROM (SELECT PlayerID, COUNT(Points)
FROM Player
WHERE Points = 1
group by PlayerID
HAVING COUNT(Points) = (SELECT MAX(count(Points))
from Player
WHERE Points = 1
group by PlayerID)) a
join TEAM b on b.playerid = a.playerid;

SQL : Count(*) and groupby with different table

I have two tables as shown below.
First Table tblCategory
Second Table tblWord
Required Output
On output,
TotalCount is count(*) with group by categoryid from tblWord
Played is count(*) with where isPlayed = 1 group by categoryid from tblword
So for getting result from 2 table, I tried following query which is wrong.
select (select count(*) from tblwords group by categoryid) as count, (select count(*) from tblwords where isPlayed = 1 group by categoryid) as played, categoryID, categoryname from tblcategory
Any suggestion in query to get required output or any helpful links ?
To get exact output with total count
SELECT t.categoryID, t.name,
COUNT(*) as TotalCount, SUM(isplayed) as Played
FROM tblCategory t
INNER JOIN tblWord tw
ON t.categoryID = tw.categoryID
GROUP BY t.categoryID, t.name
To get count for isPlayed = 1 only
SELECT t.categoryID, t.name,
COUNT(*) as TotalCount, SUM(isplayed) as Played
FROM tblCategory t
INNER JOIN tblWord tw
ON t.categoryID = tw.categoryID
WHERE isPlayed=1
GROUP BY t.categoryID, t.name
try this
SELECT tw.Category_ID, tc.NAME,
COUNT(*) AS TotalCount, SUM(tw.IsPlayed=1) AS Played ,SUM(tw.IsPlayed=0) AS NonPlayed
FROM Table_Category tc
INNER JOIN Table_Word tw
ON tc.Category_ID = tw.Category_ID
-- WHERE tw.IsPlayed=1
GROUP BY tc.Category_ID, tc.NAME
here SUM(tw.IsPlayed=1) AS Played ,SUM(tw.IsPlayed=0) AS NonPlayed is used ,so u will get the both Played and non played
select *
from
(select categoryID, count(isPlayed), sum(isPlayed) from tblword group by categoryID) b
left join
tblcategory a
on a.categoryID = b.categoryID
I'd aggregate first, then join.

sql convert rows into columns in sql server 2008r2

I have a tables called customer, hobby's.
A customer has several hobby's. So if I join my table customer with table hobby I get a result like:
[CustomerName] [HobbyName]
Harry Tennis
Harry Football
What I would like is to see a result like this:
[CustomerName] [HobbyName1] [HobbyName2]
Harry Tennis Football
My current query looks like this:
Select tCustomer.name, tHobby.name
from dbo.customer tCustomer
inner join dbo.hobby tHobby on tHobby.customerid = tCustomer.id
You didn't provide many details on your table structure but you can use PIVOT to get the final result, but in order to use this you will first want to use row_number() to generate a unique sequence for each hobby per customer:
select customer, Hobby1, Hobby2
from
(
Select c.name customer,
h.name hobby,
'Hobby'+
cast(row_number() over(partition by c.id
order by h.name) as varchar(10)) seq
from dbo.customer c
inner join dbo.hobby h
on h.customerid = c.id
) d
pivot
(
max(hobby)
for seq in (hobby1, Hobby2)
) piv;
See SQL Fiddle with Demo. If you don't want to use the PIVOT function, then you could also use a CASE expression and an aggregate function:
select customer,
max(case when seq = 1 then hobby end) hobby1,
max(case when seq = 2 then hobby end) hobby2
from
(
Select c.name customer,
h.name hobby,
row_number() over(partition by c.id
order by h.name) seq
from dbo.customer c
inner join dbo.hobby h
on h.customerid = c.id
) d
group by customer;
See SQL Fiddle with Demo

SQL Query / Herigate data join

I have two tables, the first with person data
ID
Name
The second has each person relatives
Primary Key Field
Person (references person.id)
RelativeType (mother or father)
Parent (references person.id)
I'm trying to get all the sons and grandsons of a specific person and I'm stuck integrating the grandsons in the query results. I'm using SQL Server.
Any ideas?
The query you need depends highly of how many level you have of the Parent-Child relationship. If you can change the schema, I would recommend you turn into using HierarchyId which is an SQL Server specific data type. Have a look here.
In the following, I assume you only have 2 levels. Father - Son - GrandSon
;WITH Sons AS (
SELECT pdf.Id, pdf.Name, pdd.Id ParentId, pdd.Name Parent FROM PersonData pdf
JOIN PersonRelative pr ON pdf.Id = pr.Parent
JOIN PersonData pdd ON pr.Person = pdd.Id //Selecting all Parents
)
SELECT pd.Name, s.Name Son, 'Son' Type FROM PersonData pd
JOIN Sons s on pd.Id = s.ParentId
UNION
SELECT pd.Name, gs.Name Son, 'GrandSon' Type FROM PersonData pd
JOIN Sons s on pd.Id = s.ParentId
JOIN Sons gs on s.Id = gs.ParentId
Try something like this (untested):
declare #person bigint = 123
;with cte as
(
select p.id, p.name, r.relativetype, r.parent, 0 decendantLevel
from person p
inner join relatives r
on p.id = r.person
where p.id = #person --select the ancestor who's tree we're interested in (if we don't want to include the person themselves change p.id to r.parent)
union all
select p.id, p.name, r.relativetype, r.parent, c.decendantLevel + 1
from person p
inner join relatives r
on p.id = r.person
inner join cte c
on c.id = r.parentid
)
select * from cte order by decendantLevel
Like mentioned recursive CTE is way to achieve this:
DECLARE #PersonToFind INT
SET #PersonToFind = 1
;WITH RCTE AS
(
SELECT Person, CAST('Child' AS NVARCHAR(MAX)) AS Relation
FROM PersonRelations
WHERE Father = #PersonToFind OR Mother = #PersonToFind
UNION ALL
SELECT pr.Person, 'Grand' + r.Relation
FROM PersonRelations pr
INNER JOIN RCTE r ON r.Person = pr.Mother OR r.Person = pr.Father
)
SELECT r.*, p.Name
FROM RCTE r
LEFT JOIN Person p ON r.Person = p.ID
SQLFiddle DEMO
(this is using mother and father columns before question was edited, so just change to Parent where there are Mother OR Father checks)
Thanks for all the answers, CTE was the way to go. I taked parts from every answer and ended with this
with Sons as (select P1.Person as PersonSon from Persons
join relatives as P1 on P1.Parent = Persons.Id
where Persons.Name = 'Mary')
select Id from Persons
join (
select P2.Person as PersonSon from Relatives as P2
join Sons on P2.Parent = Sons.PersonSon ) as P3 on Persons.Id = P3.PersonSon
union all select Sons.PersonSon from Sons

How to count number of different items in SQL

Database structure:
Clubs: ID, ClubName
Teams: ID, TeamName, ClubID
Players: ID, Name
Registrations: PlayerID, TeamID, Start_date, End_date, SeasonID
Clubs own several teams. Players may get registered into several teams (inside same club or into different club) during one year.
I have to generate a query to list all players that have been registered into DIFFERENT CLUBS during one season. So if player swapped teams that were owned by the same club then it doesn't count.
My attempts so far:
SELECT
c.short_name,
p.surname,
r.start_date,
r.end_date,
(select count(r2.id) from ejl_registration as r2
where r2.player_id=r.player_id and r2.season=r.season) as counter
FROM
ejl_registration AS r
left Join ejl_players AS p ON p.id = r.player_id
left Join ejl_teams AS t ON r.team_id = t.id
left Join ejl_clubs AS c ON t.club_id = c.id
WHERE
r.season = '2008'
having counter >1
I can't figure out how to count and show only different clubs... (It's getting too late for clear thinking). I use MySQL.
Report should be like: Player name, Club name, Start_date, End_date
This is a second try at this answer, simplifying it to merely count the distinct clubs, not report a list of club names.
SELECT p.surname, r.start_date, r.end_date, COUNT(DISTINCT c.id) AS counter
FROM ejl_players p
JOIN ejl_registration r ON (r.player_id = p.id)
JOIN ejl_teams t ON (r.team_id = t.id)
JOIN ejl_clubs c ON (t.club_id = c.id)
WHERE r.season = '2008'
GROUP BY p.id
HAVING counter > 1;
Note that since you're using MySQL, you can be pretty flexible with respect to columns in the select-list not matching columns in the GROUP BY clause. Other brands of RDBMS are more strict about the Single-Value Rule.
There's no reason to use a LEFT JOIN as in your example.
Okay, here's the first version of the query:
You have a chain of relationships like the following:
club1 <-- team1 <-- reg1 --> player <-- reg2 --> team2 --> club2
Such that club1 must not be the same as club2.
SELECT p.surname,
CONCAT_WS(',', GROUP_CONCAT(DISTINCT t1.team_name),
GROUP_CONCAT(DISTINCT t2.team_name)) AS teams,
CONCAT_WS(',', GROUP_CONCAT(DISTINCT c1.short_name),
GROUP_CONCAT(DISTINCT c2.short_name)) AS clubs
FROM ejl_players p
-- Find a club where this player is registered
JOIN ejl_registration r1 ON (r1.player_id = p.id)
JOIN ejl_teams t1 ON (r1.team_id = t1.id)
JOIN ejl_clubs c1 ON (t1.club_id = c1.id)
-- Now find another club where this player is registered in the same season
JOIN ejl_registration r2 ON (r2.player_id = p.id AND r1.season = r2.season)
JOIN ejl_teams t2 ON (r2.team_id = t2.id)
JOIN ejl_clubs c2 ON (t2.club_id = c2.id)
-- But the two clubs must not be the same (use < to prevent duplicates)
WHERE c1.id < c2.id
GROUP BY p.id;
Here's a list of players for one season.
SELECT sub.PlayerId
FROM
(
SELECT
r.PlayerId,
(SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
FROM Registrations r
WHERE r.Season = '2008'
) as sub
GROUP BY PlayerId
HAVING COUNT(DISTINCT sub.ClubID) > 1
Here's a list of players and seasons, for all seasons.
SELECT PlayerId, Season
FROM
(
SELECT
r.PlayerId,
r.Season,
(SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
FROM Registrations r
) as sub
GROUP BY PlayerId, Season
HAVING COUNT(DISTINCT sub.ClubID) > 1
By the way, this works in MS SQL.
SELECT p.Name, x.PlayerID, x.SeasonID
FROM (SELECT DISTINCT r.PlayerID, r.SeasonID, t.ClubID
FROM Registrations r
JOIN Teams t ON t.ID = r.TeamID) x
JOIN Players p ON p.ID = x.PlayerID
GROUP BY p.rName, x.PlayerID, x.SeasonID
HAVING COUNT(*) > 1