简体   繁体   English

不使用join获取sql查询结果

[英]Get sql query result without using join

I've below tables players, matches.我在桌子下面有球员,比赛。

player_id | group_id
 -----------+----------
 20       |   2
 30       |   1
 40       |   3
 45       |   1
 50       |   2
 65       |   1

match_id | first_player | second_player | first_score | second_score
 ----------+--------------+---------------+-------------+--------------
 1       |    30        |       45      |      10     |     12
 2       |    20        |       50      |      5      |     5
 13      |    65        |       45      |      10     |     10
 5       |    30        |       65      |      3      |     15
 42      |    45        |       65      |      8      |     4

Desired result:期望的结果:

group_id | winner_id
 ----------+-----------
   1     |  45
   2     |  20
   3     |  40

Below are cases:以下为案例:

  1. In group 1 the winner is player 45 with the total score of 30 points.在第 1 组中,获胜者是 45 号选手,总得分为 30 分。
  2. In group 2 both players scored 5 points, but player 20 has lower ID and is a winner.在第 2 组中,两位玩家都获得了 5 分,但玩家 20 的 ID 较低并且是赢家。
  3. In group 3 there is only one player, and although she didn't play any matches, she is a winner.第三组只有一名选手,虽然她没有参加任何比赛,但她是赢家。

I have written below query with left join & it satisfies all the 3 cases.我在下面用左连接写了查询,它满足所有 3 种情况。 But I need query without any join .但是我需要没有任何连接的查询。

Below is query for reference:以下查询供参考:

select group_id,player_id,totalScores from
 (select group_id,player_id,sum((
  case when player_id = first_player then first_score
   when player_id = second_player then second_score
   end
)) as totalScores

from players p
left join matches m on (p.player_id = m.first_player or p.player_id = m.second_player)

group by group_id,player_id
order by group_id,totalScores desc,player_id ) as temp
group by group_id
order by group_id,totalScores desc,player_id

Your query is invalid.您的查询无效。 In the main query you group by group_id only, but select a player_id and totalScores.在主查询中,您仅按 group_id 分组,但选择了 player_id 和 totalScores。 Which player_id?哪个player_id? Which totalScores?哪些总分? There can be many per group_id.每个 group_id 可以有很多。 MySQL should raise an error here, and if it doesn't this indicaes that you are working in MySQL's notorious cheat mode that silently applies the ANY_VALUE function on such columns. MySQL 应该在此处引发错误,如果没有,则表明您正在使用 MySQL 臭名昭著的作弊模式,该模式会在此类列上静默应用ANY_VALUE函数。 Don't do that.不要那样做。 You get arbitrarily chosen values that can even stem from different rows.您会得到任意选择的值,这些值甚至可以来自不同的行。 In MySQL, always在 MySQL 中,总是

SET sql_mode = 'ONLY_FULL_GROUP_BY';

in order not to be allowed to write invalid queries.为了不被允许写无效的查询。

Apart from that, you have an ORDER BY clause in a subquery.除此之外,您在子查询中有一个ORDER BY子句。 A subquery cannot be ordered, and in fact, some DBMS would raise an error here.无法对子查询进行排序,事实上,某些 DBMS 会在此处引发错误。 Subquery results are unordered sets of data by definition.根据定义,子查询结果是无序数据集。

If run in MySQL cheat mode, your query selects one row per group_id, each which an arbitrarily chosen player_id and and arbitrarily chosen total score.如果在 MySQL 作弊模式下运行,您的查询会为每个 group_id 选择一行,其中每一行都是任意选择的 player_id 和任意选择的总分。 This is not what you want.这不是你想要的。

Here is a query that solves the task properly.这是正确解决任务的查询。 It joins the tables as in your query, but then ranks the players by group_id with ROW_NUMBER .它按照您的查询加入表格,但随后按 group_id 和ROW_NUMBER对玩家进行排名。 At last it shows the highest ranked player per group.最后它显示了每组排名最高的玩家。

with scores as
(
  select
    p.group_id,
    p.player_id,
    coalesce(sum(case when player_id = first_player then first_score else second_score end), 0) as score
  from players p
  left join matches m on p.player_id in (m.first_player, m.second_player)
  group by p.group_id, p.player_id
)
, ranked as
(
  select group_id, player_id,
    row_number() 
      over(partition by group_id order by score desc, player_id) as rn
  from scores
)
select group_id, player_id
from ranked
where rn = 1
order by group_id;

(You could rank right away, but I thought it more readable to build the sums first and then rank in a separate step.) (您可以立即排名,但我认为先计算总和然后在单独的步骤中排名更具可读性。)

As you say you don't want to join (which seems a very weird request) and you only need the players' total scores from the matches table, you can replace the outer join by a subquery in the players' select clause:正如你所说你不想加入(这似乎是一个非常奇怪的请求)并且你只需要比赛表中球员的总分,你可以用球员选择子句中的子查询替换外部连接:

with scores as
(
  select
    group_id,
    player_id,
    (
      select coalesce(sum(case when player_id = first_player then first_score else second_score end), 0)
      from matches m
      where p.player_id in (m.first_player, m.second_player)
    ) as score
  from players p
)

Demo: https://dbfiddle.uk/PxP_gMXI演示: https ://dbfiddle.uk/PxP_gMXI

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM