我正在努力为某个人确定有多少人获得了比他们更好的分数,并将其归入他们所属的不同团队。因此,在下表中,我从team_id
表中抓取team_person
列表,其中person_id与我关心的人匹配。这将使我成为我所有的球队。
然后我需要知道我所属的任何团队中的每个person_id
,以便我可以从score
表中找出他们的最大performances
。
一旦我拥有了这一点,我终于想确定,对于每个team_id
,该团队中有多少人拥有比我更好的分数,其中更好的被简单地定义为具有更大的价值。
此时我已经超越了SQL的能力。到目前为止我所拥有的,似乎让我所关心的所有人的最高分,(基本上除了我的最终“团队”要求之外的一切)是这样的:
SELECT person_id, MAX(score) m
FROM performances
WHERE category_id = 7 AND person_id IN (
-- Find all the people on the teams I belong to
SELECT DISTINCT person_id
FROM team_person
WHERE team_id IN (
-- Find all the teams that I belong to
SELECT DISTINCT team_id
FROM team_person
WHERE person_id = 2
)
)
GROUP BY person_id
ORDER BY 2 DESC
我的两个相关表是这样定义的,我正在使用psql 9.1.15
Table "public.team_person"
Column | Type | Modifiers
------------+--------------------------+-------------------------------------------------------------
ident | integer | not null default nextval('team_person_ident_seq'::regclass)
team_id | integer | not null
person_id | integer | not null
*chop extraneous columns*
Indexes:
"team_person_pkey" PRIMARY KEY, btree (ident)
"teamPersonUnique" UNIQUE CONSTRAINT, btree (team_id, person_id)
Foreign-key constraints:
"team_person_person_id_fkey" FOREIGN KEY (person_id) REFERENCES person(ident) ON DELETE CASCADE
"team_person_team_id_fkey" FOREIGN KEY (team_id) REFERENCES team(ident) ON DELETE CASCADE
Referenced by:
TABLE "roster" CONSTRAINT "roster_team_person_id_fkey" FOREIGN KEY (team_person_id) REFERENCES team_person(ident) ON DELETE SET NULL
Triggers:
update_team_person_modified BEFORE INSERT OR UPDATE ON team_person FOR EACH ROW EXECUTE PROCEDURE update_modified_column()
Table "public.performances"
Column | Type | Modifiers
-------------+--------------------------+--------------------------------------------------------------
ident | bigint | not null default nextval('performances_ident_seq'::regclass)
category_id | integer | not null
person_id | integer | not null
score | real | not null
*chop extraneous columns*
Indexes:
"performances_pkey" PRIMARY KEY, btree (ident)
Foreign-key constraints:
"performances_category_id_fkey" FOREIGN KEY (category_id) REFERENCES performance_categories(ident) ON DELETE CASCADE
"performances_person_id_fkey" FOREIGN KEY (person_id) REFERENCES person(ident) ON DELETE CASCADE
答案 0 :(得分:1)
首先,说明问题,而不是关于如何获得解决方案的假设。你做得很好:
确定某个人有多少人获得比他们更好的分数,并根据他们所属的不同团队对其进行分组。
但我改了一下:
对于每个团队,某个人是其中的一员,该团队中有多少人的得分高于该人?
我不了解你,但现在突然变得简单了。参加团队排名,左外连接team_person并过滤我们所属的团队,左外连接表演以找到我们与该团队一起玩的游戏,再次离开外部加入team_person以获得其他成员的成员每个团队,左外连接表演,过滤团队主体人员不是成员,团体和聚合。
对于一些极端情况(例如你是唯一的成员,或者你没有玩过游戏的团队),它没有明确规定,但 eh ,无论如何。
问题:
没有团队表。由于您不关心团队表中的任何内容,因此您可以从联接中省略它,只需使用team_person
作为连接根。
顺便说一句,您的team_person
表格有缺陷。它应该UNIQUE
上有(team_id, person_id
约束。或者,更好的是,应该是primary key
。对于此查询而言实际上并不重要,因为重复的团队成员资格不会改变结果,但却是错误的数据建模。您不能多次成为团队成员。
performances
还应该有一个标识特定游戏或其他内容的列。由于你没有表现出一个,我会假设你在寻找那些在任何游戏中,在该游戏或其他游戏中至少表现过一次的人比其他人更好的人游戏。如果您确实想要找到在特定游戏中做得更好的人,那么您需要performances
上的合适密钥。
致命问题:performances
也缺少一个将效果与团队相关联的列。这使得无法正确解决问题,因为您无法在特定团队中获得特定人员的表演。我假设team_id
实际上有一个performances
,你就把它遗弃了。
因此,考虑到上述问题,我首先使用大型连接获取数据,然后对其进行分组和聚合。对于我们参加的每个团队,这次参加将为我们的每个演出,每个其他演奏者,每个其他演出,一行提供所有相关信息。然后,您可以比较性能和聚合。
以下内容完全未经测试,因为您没有提供示例数据,并且您从架构中删除了重要部分(或架构有缺陷),但我尝试过类似的事情:
SELECT
my_performances.team_id,
-- Find how many distinct people scored better than us at least once,
-- no matter how many times or in which game.
COUNT(distinct other_team_person.person_id)
-- Start the join with our team memberships and how we scored in each.
-- If we didn't play any games for this team don't produce a result row
-- for it, so INNER JOIN.
FROM team_person my_team_person
INNER JOIN performances my_performances ON
(my_performances.person_id = my_team_person.person_id
AND my_performances.team_id = my_team_person.team_id)
-- Other members of teams we're also a member of, skipping
-- ourselves. An `INNER JOIN` is fine here because we know
-- a team with only ourselves as a member isn't interesting
-- and we might as well skip it.
INNER JOIN team_person others_team_person ON (
my_team_person.team_id = other_team_person.team_id
AND my_team_person.person_id <> other_team_person.person_id)
-- How each of those people performed in each team they're in
-- (because of previous filter, only considers teams we're in too).
-- INNER JOIN because if they never played they can't beat us.
INNER JOIN performances other_performances ON (
other_team_person.person_id = other_performances.person_id
AND other_team_person.team_id = other_performances.team_id)
-- Make sure `my_team_person` is only teams we're a member of
WHERE my_team_person.person_id = $1
-- Also discard rows where the other person didn't do better than us
AND my_performances.score < other_performances.score
-- Emit one row per team we're a member of
GROUP BY my_performances.team_id;
如果你想展示你从未参加过比赛的球队和你唯一的球员,那么你需要将INNER JOIN
更改为LEFT OUTER JOIN
。
如果您想进行比较以查找仅在特定游戏中击败您的人,您需要在performances
上添加一个额外的列,然后在{{1}的联接中添加一个额外的列限制它仅在与other_performances
相同的游戏中匹配。