8

在此查询中,我必须列出为完全相同的球队效力的一对球员及其 playerID 和 playerName。如果一名球员为 3 支球队效力,则另一个必须为完全相同的 3 支球队效力。不多,不多。如果两名球员目前没有为任何球队效力,他们也应该被包括在内。查询应返回 (playerID1, playername1, playerID2, playerName2) 且不重复,例如如果玩家 1 信息出现在玩家 2 之前,则不应有另一个元组包含玩家 2 信息在玩家 1 之前。

例如,如果球员 A 为洋基队和红袜队效力,球员 b 为洋基队、红袜队和道奇队效力,我不应该得到他们。他们都必须为洋基队和红袜队效力,而没有其他人。现在,如果球员为任何同一支球队效力,这个查询可以找到答案。

Tables:
player(playerID: integer, playerName: string)
team(teamID: integer, teamName: string, sport: string)
plays(playerID: integer, teamID: integer)

Example data:
PLAYER    
playerID    playerName
1           Rondo
2           Allen
3           Pierce
4           Garnett
5           Perkins

TEAM      
teamID     teamName       sport
1          Celtics        Basketball
2          Lakers         Basketball
3          Patriots       Football
4          Red Sox        Baseball
5          Bulls          Basketball

PLAYS
playerID    TeamID
1           1
1           2
1           3
2           1
2           3
3           1
3           3

所以我应该得到这个作为答案-

 2, Allen, 3, Pierce 
 4, Garnett, 5, Perkins

.

2,阿伦,3 皮尔斯是一个答案,因为他们都只为凯尔特人和爱国者队效力。 4,加内特,5,帕金斯是一个答案,因为这两名球员都没有为应该输出的球队效力。

现在我的查询是

SELECT p1.PLAYERID, 
       f1.PLAYERNAME, 
       p2.PLAYERID, 
       f2.PLAYERNAME 
FROM   PLAYER f1, 
       PLAYER f2, 
       PLAYS p1 
       FULL OUTER JOIN PLAYS p2 
                    ON p1.PLAYERID < p2.PLAYERID 
                       AND p1.TEAMID = p2.TEAMID 
GROUP  BY p1.PLAYERID, 
          f1.PLAYERID, 
          p2.PLAYERID, 
          f2.PLAYERID 
HAVING Count(p1.PLAYERID) = Count(*) 
       AND Count(p2.PLAYERID) = Count(*) 
       AND p1.PLAYERID = f1.PLAYERID 
       AND p2.PLAYERID = f2.PLAYERID; 

我不是 100% 确定,但我认为这可以找到为同一支球队效力的球员,但我想找出为上述相同球队效力的球员

我被困在如何处理它之后。有关如何解决此问题的任何提示。谢谢你的时间。

4

16 回答 16

4

我相信这个查询会做你想要的:

SELECT array_agg(players), player_teams
FROM (
  SELECT DISTINCT t1.t1player AS players, t1.player_teams
  FROM (
    SELECT
      p.playerid AS t1id,
      concat(p.playerid,':', p.playername, ' ') AS t1player,
      array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
    FROM player p
    LEFT JOIN plays pl ON p.playerid = pl.playerid
    GROUP BY p.playerid, p.playername
  ) t1
INNER JOIN (
  SELECT
    p.playerid AS t2id,
    array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
  FROM player p
  LEFT JOIN plays pl ON p.playerid = pl.playerid
  GROUP BY p.playerid, p.playername
) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id
) innerQuery
GROUP BY player_teams


Result:
PLAYERS               PLAYER_TEAMS
2:Allen,3:Pierce      1,3
4:Garnett,5:Perkins

它使用 array_agg 代替每个玩家的 teamidplays来匹配具有完全相同团队配置的玩家。例如,我在团队中包含了一个列,但只要不从 group by 子句中删除它就可以在不影响结果的情况下删除它。

SQL 小提琴示例。用 Postgesql 9.2.4 测试

编辑:修复了重复行的错误。

于 2013-07-31T08:31:04.283 回答
1

没什么大不了的,这是解决方案

with gigo as(select a.playerid as playerid,count(b.teamname) as nteams from player a 
full outer join plays c on a.playerid=c.playerid full outer join team b 
on b.teamid=c.teamid group by a.playerid)
select array_agg(a.*),g.nteams from player a inner join gigo g on a.playerid=g.playerid 
group by g.nteams having count(a.*)>1 order by g.nteams desc
于 2014-01-16T07:11:04.340 回答
1

似乎 OP 可能不再感兴趣了,但如果其他人觉得它有用,这是纯 SQL 中的查询(至少对我来说;))

SELECT M.p1, pr1.playername, M.p2, pr2.playername FROM player pr1 
INNER JOIN player pr2 INNER JOIN
(
   SELECT plays1.player p1, plays2.player p2, plays1.team t1 FROM plays plays1 
   INNER JOIN plays plays2 
   ON (plays1.player < plays2.player AND plays1.team = plays2.team)
   GROUP BY plays1.player, plays2.player HAVING COUNT(*) = 
((SELECT COUNT(*) FROM plays plays3 WHERE plays3.player = plays1.player) + 
(SELECT COUNT(*) FROM plays plays4 WHERE plays4.player = plays2.player)) /2
) M ON pr1.playerID = M.p1 AND pr2.playerID = M.p2 
UNION ALL
SELECT M.pid, M.pname, N.pid2, N.pname2 FROM
(
(SELECT p.playerID pid, p.playerName pname, pl.team FROM player p
 LEFT JOIN plays pl ON p.playerId = pl.player WHERE pl.team IS NULL) M
 INNER JOIN
 (SELECT p.playerID pid2, p.playerName pname2, pl.team FROM player p
  LEFT JOIN plays pl ON p.playerId = pl.player WHERE pl.team IS NULL) N 
 ON (pid < pid2)
)
于 2013-11-09T22:47:05.977 回答
1

这个解决方案对我有用:

SELECT TMP1. PLAYERID,TMP2.PLAYERID FROM
(
    SELECT a.playerid , a.teamid,b.team_sum 
    FROM plays  A
    INNER JOIN 
    (
        SELECT PLAYERID,SUM(teamid) AS team_sum
        FROM plays
        GROUP BY 1
     ) B

    ON a.playerid=b.playerid
 ) TMP1

INNER JOIN

(
    SELECT a.playerid , a.teamid,b.team_sum
    FROM plays  A

    INNER JOIN 
    (
        SELECT PLAYERID,SUM(teamid) AS team_sum
        FROM plays
        GROUP BY 1
    ) B

ON a.playerid=b.playerid

)TMP2
ON TMP1.PLAYERID < TMP2.PLAYERID
AND TMP1.TEAMID=TMP2.TEAMID
AND TMP1.TEAM_SUM=TMP2.TEAM_SUM
GROUP BY 1,2

UNION ALL
SELECT n1,n2 FROM  
(
    SELECT TMP3.PLAYERID AS n1,TMP4.PLAYERID AS n2 FROM 
    PLAYER  TMP3
    INNER JOIN PLAYER TMP4
    ON TMP3.PLAYERID<TMP4.PLAYERID
    WHERE TMP3.PLAYERID  NOT IN (SELECT  PLAYERID FROM plays  )
    AND tmp4.playerid NOT IN (SELECT playerid FROM plays)
) TMP5
于 2015-05-11T05:41:21.763 回答
0

这是使用 UNION 和 2-3 个简单连接的简单查询。UNION 之前的第一个查询包含为相同数量的球队效力相同次数的球员姓名和球员ID。UNION 之后的第二个查询包含根本没有为任何球队效力的球员姓名和球员 ID。

只需复制粘贴此查询并尝试执行它,您将看到预期的结果。

    select playername,c.playerid from 
    (select a.cnt, a.playerid from 
    (select count(1) cnt , PLAYERID from plays group by  PLAYERID) a ,
    (select count(1) cnt , PLAYERID from plays group by  PLAYERID) b 
    where a.cnt=b.cnt
    and  a.playerid<> b.playerid ) c ,PLAYER  d
    where c.playerid=d.playerid
    UNION
    select e.playername,e.playerid 
    from player e 
    left outer join plays f on 
    e.playerid=f.playerid where nvl(teamid,0 )=0
于 2014-07-02T06:02:43.913 回答
0

select p1.playerId, p2.playerId, count(p1.playerId)
from plays p1, plays p2
WHERE p1.playerId<p2.playerId
and p1.teamId = p2.teamId
GROUP BY p1.playerId, p2.playerId
having count(*) = (select count(*) from plays where playerid = p1.playerid)

于 2015-03-04T17:58:55.363 回答
0

对于任何感兴趣的人,这个简单的查询对我有用

SELECT UNIQUE PLR1.PID,PLR1.PNAME, PLR2.PID, PLR2.PNAME
FROM PLAYS PLY1,PLAYS PLY2, PLAYER PLR1, PLAYER PLR2
WHERE PLR1.PID < PLR2.PID AND PLR1.PID = PLY1.PID(+) AND PLR2.PID = PLY2.PID(+)
AND NOT EXISTS(( SELECT PLY3.TEAMID FROM PLAYS PLY3 WHERE PLY3.PID = PLR1.PID) 
MINUS
( SELECT PLY4.TEAMID FROM PLAYS PLY4 WHERE PLY4.PID = PLR2.PID));
于 2014-12-28T06:21:48.900 回答
0

您想要的基本数据类型似乎是集合,而不是数组。因此,一种选择可能是使用 PL/Python 的代码类似于下面的代码(有关可能适用于此目的的函数,请参阅此答案的底部)。当然,这绝不是一种“纯 SQL”方法。

但坚持使用 PostgreSQL(尽管不是标准 SQL),您可能还希望将 DISTINCT 与 array_agg 一起使用。请注意,以下仅给出符合条件的第一对(原则上可能有更多)。

WITH teams AS (
  SELECT playerID, array_agg(DISTINCT teamID ORDER BY teamID) AS teams
  FROM plays
  GROUP BY playerID),
teams_w_nulls AS (
  SELECT a.playerID, b.teams
  FROM player AS a
  LEFT JOIN teams AS b
  ON a.playerID=b.playerID),
player_sets AS (
  SELECT teams, array_agg(DISTINCT playerID ORDER BY playerID) AS players
  FROM teams_w_nulls
  GROUP BY teams
  -- exclude players who are only share a team list with themselves.
  HAVING array_length(array_agg(DISTINCT playerID ORDER BY playerID),1)>1)
SELECT a.teams, b.playerID, b.playerName, c.playerID, c.playerName
FROM player_sets AS a
INNER JOIN player AS b
ON a.players[1]=b.playerID
INNER JOIN player AS c
ON a.players[2]=c.playerID;

上面的查询给出以下输出:

 teams | playerid | playername | playerid | playername 
-------+----------+------------+----------+------------
 {1,3} |        2 | Allen      |        3 | Pierce
       |        4 | Garnett    |        5 | Perkins
(2 rows)

PL/Python 函数示例:

CREATE OR REPLACE FUNCTION set(the_list integer[])
  RETURNS integer[] AS
$BODY$
    return list(set(the_list))
$BODY$
  LANGUAGE plpython2u;

CREATE OR REPLACE FUNCTION pairs(a_set integer[])
  RETURNS SETOF integer[] AS
$BODY$
    def pairs(x):
        for i in range(len(x)):
            for j in x[i+1:]:
                yield [x[i], j]
    return list(pairs(a_set))
$BODY$
  LANGUAGE plpython2u;

SELECT set(ARRAY[1, 1, 2, 3, 4, 5, 6, 6]);

上面使用这些函数的代码版本(输出类似,但是当给定的一组团队有多个配对时,这种方法会选择所有配对):

WITH teams AS (
  SELECT playerID, set(array_agg(teamID)) AS teams
  FROM plays
  GROUP BY playerID),
teams_w_nulls AS (
  SELECT a.playerID, b.teams
  FROM player AS a
  LEFT JOIN teams AS b
  ON a.playerID=b.playerID),
player_pairs AS (
  SELECT teams, pairs(set(array_agg(playerID))) AS pairs
  FROM teams_w_nulls
  GROUP BY teams)
  -- no need to exclude players who are only share a team 
  -- list with themselves.
SELECT teams, pairs[1] AS player_1, pairs[2] AS player_2
FROM player_pairs;
于 2013-07-31T17:09:30.340 回答
0

想到了两种可能的解决方案:

  1. 光标 - 遍历每个玩家并将他与所有其他玩家进行比较,直到得出结论。
  2. 递归查询 - 相同的想法虽然稍微复杂一些,但绝对是更好的方法。可能也有更好的表现。

您能否提供一些示例数据以便我创建示例?

于 2013-07-31T07:02:20.350 回答
0

我们使用每个球员的球队数和 ascii(team_name)+team_id 的总和进行查询,将其称为 team_value。我们做一个自连接,与自身相同的查询,其中 counts 和 team_values 匹配但 id 不等于 id,这给了我们想要获取的 ID

select * from player where player_id in 
(
 select set2.player_id orig
 from
 (select count(*) count,b.player_id , nvl(sum(a.team_id+ascii(team_name)),0) team_value
   from plays a, player b , team c
   where a.player_id(+)=b.player_id
    and a.team_id = c.team_id(+)
   group by b.player_id) set1,
(select count(*) count,b.player_id , nvl(sum(a.team_id+ascii(team_name)),0) team_value
   from plays a, player b , team c
   where a.player_id(+)=b.player_id
    and a.team_id = c.team_id(+)
   group by b.player_id) set2
where set1.count=set2.count and set1.team_value=set2.team_value
  and set1.player_id<>set2.player_id
)
于 2014-01-04T13:43:45.863 回答
0
WITH temp AS (
  SELECT p.playerid, p.playername, listagg(t.teamname,',') WITHIN GROUP (ORDER BY t.teamname) AS teams
  FROM player p full OUTER JOIN plays p1 ON p.playerid = p1.playerid
    LEFT JOIN team t ON p1.teamid = t.teamid GROUP BY (p.playerid , p.playername))
SELECT concat(concat(t1.playerid,','), t1.playername), t1.teams 
FROM temp t1 WHERE nvl(t1.teams,' ') IN (
  SELECT nvl(t2.teams,' ') FROM temp t2 
  WHERE t1.playerid <> t2.playerid) 
ORDER BY t1.playerid
于 2015-04-16T10:59:28.027 回答
0

试试这个:这里的测试是你问题中的 PLAYS 表。

select group_concat(b.name),a.teams from
(SELECT playerid, group_concat(distinct teamid ORDER BY teamid) AS teams
  FROM test
  GROUP BY playerid) a, player b
where a.playerid=b.playerid
group by a.teams
union
select group_concat(c.name order by c.playerid),null from player c where c.playerid not in (select        playerid from test);
于 2014-10-16T18:54:56.107 回答
0

这是 ANSI SQL ,不使用任何特殊功能。

SELECT   TAB1.T1_playerID AS playerID1 , TAB1.playerName1  ,   
  TAB1.T2_playerID AS playerID2, TAB1. playerName2
 FROM
(select   T1.playerID AS T1_playerID ,  T3. playerName  AS  playerName1 ,

T2.playerID  AS T2_playerID ,  T4. playerName AS playerName2  ,COUNT (T1.TeamID) AS MATCHING_TEAM_ID_CNT
FROM PLAYS T1
INNER JOIN PLAYS T2  ON(  T1.TeamID = T2.TeamID AND T1.playerID <> T2.playerID )
INNER JOIN player T3 ON (  T1.playerID=T3.playerID)
INNER JOIN player T4 ON (  T2.playerID=T4.playerID)
 GROUP BY 1,2,3,4
) TAB1

INNER JOIN 
( SELECT  T1.playerID AS playerID, COUNT(T1.TeamID) AS TOTAL_TEAM_CNT
 FROM PLAYS  T1
GROUP BY T1.playerID) TAB2
ON(TAB1.T2_playerID=TAB2.playerID AND    
  TAB1.MATCHING_TEAM_ID_CNT =TAB2.TOTAL_TEAM_CNT)

INNER JOIN 
( SELECT  T1.playerID AS playerID, COUNT(T1.TeamID) AS TOTAL_TEAM_CNT
FROM PLAYS  T1
GROUP BY T1.playerID 
) TAB3
ON( TAB1. T1_playerID = TAB3.playerID  AND 
 TAB1.MATCHING_TEAM_ID_CNT=TAB3.TOTAL_TEAM_CNT)
WHERE playerID1  < playerID2

    UNION ALL (
    SELECT   T1.playerID, T1.playerName ,T2.playerID,T2.playerName
    FROM
    PLAYER T1 INNER JOIN PLAYER T2
    ON (T1.playerID<T2.playerID) 
    WHERE T1.playerID NOT IN ( SELECT playerID FROM PLAYS))
于 2015-05-11T05:58:11.707 回答
0

假设您的 teamId 是唯一的,此查询将起作用。它只是通过对 teamid 求和来识别具有完全相同球队的所有球员,或者如果球员没有 id,则它将为空。然后计算团队比赛的比赛次数。我在 postgre 9.3 中使用 SQL fiddle 进行了测试。

SELECT 
     b.playerID
    ,b.playerName
FROM (
--Join the totals of teams to your player information and then count over the team matches.
        SELECT 
                p.playerID
                ,p.playerName
                ,m.TeamMatches
                ,COUNT(*) OVER(PARTITION BY TeamMatches) as Matches
        FROM player p
                LEFT JOIN (
                --Assuming your teamID is unique as it should be. If it is then a sum of the team ids for a player will give you each team they play for. 
                --If for some reason your team id is not unique then rank the table and join same as below. 
                    SELECT 
                         ps.playerName
                        ,ps.playerID
                        ,SUM(t.teamID) as TeamMatches
                    FROM plays p
                            LEFT JOIN team t ON p.teamID = p.teamID
                            LEFT JOIN player ps ON p.playerID = ps.playerID
                    GROUP BY 
                            ps.playerName
                        ,ps.playerID
                ) m ON p.playerID = m.playerID
) b
WHERE
b.Matches <> 1
于 2015-10-04T02:50:56.413 回答
-1

这个查询应该解决它。通过在 PLAYS 上进行自我加入。- 比较玩家 ID - 将匹配的行数与每个玩家的总计数进行比较。

select p1.playerId, p2.playerId, count(p1.playerId)
from plays p1, plays p2
WHERE p1.playerId<p2.playerId
and p1.teamId = p2.teamId
GROUP BY p1.playerId, p2.playerId
having count(*) = (select count(*) from plays where playerid = p1.playerid)

于 2015-02-21T19:22:54.183 回答
-2

在 SQL 2008 中创建函数

ALTER FUNCTION [dbo].[fngetTeamIDs] ( @PayerID int ) RETURNS varchar(101) AS Begin

declare @str varchar(1000)

SELECT @str= coalesce(@str + ', ', '') + CAST(a.TeamID AS varchar(100)) FROM (SELECT DISTINCT TeamID from Plays where PayerId=@PayerID) a

return @str

END

--select dbo.fngetTeamIDs(2)

查询从这里开始

drop table #temp,#A,#B,#C,#D

(select PayerID,count(*) count 
into #temp
from Plays 
group by PayerID)


select *
into #A
from #temp as T

where T.count in (
        select T1.count from #temp as T1
        group by T1.count having count(T1.count)>1 
)

select A.*,P.TeamID
into #B
from #A A inner join Plays P
on A.PayerID=P.PayerID
order by A.count


select B.PayerId,B.count, 
(
select dbo.fngetTeamIDs(B.PayerId)
) as TeamIDs
into #C
from #B B
group by B.PayerId,B.count


select TeamIDs 
into #D
from #c as C
group by C.TeamIDs
having count(C.TeamIDs)>1

select C.PayerId,P.PlayerName,D.TeamIDs
from #D D inner join #C C
on D.TeamIDs=C.TeamIDs
inner join Player P
on C.PayerID=P.PlayerID
于 2015-09-04T11:34:49.137 回答