[英]PostgresQL: Finding records that do not exist in query
下面,我查询了排行榜中玩家的排名表。
球员信息(包括pseudonym
)存储在player
表中,而每个“比赛日”的排名(由edition_id
标识)存储在players_rankings
中,因为比赛是线性的(没有积分系统,因此无法以数学方式计算排名)。 每个夹具的信息存储在set
中( sw
表示胜局,而sl
表示败局)。
SELECT
players_rankings.rank, players_rankings.change, player.pseudonym,
SUM(tot.sw) AS sw,
SUM(tot.sl) AS sl
FROM players_rankings, player, (
SELECT
player1_id AS player_id,
CASE
WHEN score1 > score2 THEN 1 ELSE 0
END AS sw,
CASE
WHEN score1 < score2 THEN 1 ELSE 0
END AS sl
FROM set WHERE edition_id = 1
UNION ALL
SELECT
player2_id,
CASE
WHEN score1 < score2 THEN 1 ELSE 0
END,
CASE
WHEN score1 > score2 THEN 1 ELSE 0
END
FROM set WHERE edition_id = 1
) AS tot
WHERE
players_rankings.edition_id = 1 AND
tot.player_id = players_rankings.player_id AND
players_rankings.player_id = player.id
GROUP BY 1, 2, 3
UNION
SELECT players_rankings.rank, players_rankings.change, player.pseudonym, 0, 0
FROM players_rankings, player
WHERE
players_rankings.edition_id = 1 AND
players_rankings.player_id = player.id
ORDER BY 1;
这会产生以下结果:
-----+--------+---------------+----+----+
rank | change | pseudonym | sw | sl |
-----+--------+---------------+----+----+
1 | 0 | Player One | 1 | 0 |
-----+--------+---------------+----+----+
1 | 0 | Player One | 0 | 0 |
-----+--------+---------------+----+----+
2 | 0 | Player Two | 0 | 0 |
-----+--------+---------------+----+----+
3 | 2 | Player Three | 1 | 0 |
-----+--------+---------------+----+----+
3 | 2 | Player Three | 0 | 0 |
-----+--------+---------------+----+----+
4 | -1 | Player Four | 0 | 1 |
-----+--------+---------------+----+----+
4 | -1 | Player Four | 0 | 0 |
-----+--------+---------------+----+----+
5 | -1 | Player Five | 1 | 0 |
-----+--------+---------------+----+----+
5 | -1 | Player Five | 0 | 0 |
-----+--------+---------------+----+----+
6 | 3 | Player Six | 0 | 0 |
-----+--------+---------------+----+----+
6 | 3 | Player Six | 1 | 0 |
-----+--------+---------------+----+----+
7 | -1 | Player Seven | 0 | 0 |
-----+--------+---------------+----+----+
7 | -1 | Player Seven | 0 | 1 |
-----+--------+---------------+----+----+
8 | -1 | Player Eight | 0 | 0 |
-----+--------+---------------+----+----+
8 | -1 | Player Eight | 0 | 1 |
-----+--------+---------------+----+----+
9 | -1 | Player Nine | 0 | 0 |
-----+--------+---------------+----+----+
10 | 0 | Player Ten | 0 | 1 |
-----+--------+---------------+----+----+
10 | 0 | Player Ten | 0 | 0 |
-----+--------+---------------+----+----+
11 | 0 | Player Eleven | 0 | 0 |
-----+--------+---------------+----+----+
12 | 0 | Player Twelve | 0 | 0 |
-----+--------+---------------+----+----+
我在UNION
之后查询的目标是只获取第一个“比赛日”中没有出现的注册球员( players_rankings.edition_id = 1
,即球员 2、9、11 和 12),但我碰壁了尝试不同的方法来实现这一点,包括不同的JOIN
。 因此,我回到绘图板并使用上述查询重新开始使用重复值,如上所示。 下面是期望的结果:
-----+--------+---------------+----+----+
rank | change | pseudonym | sw | sl |
-----+--------+---------------+----+----+
1 | 0 | Player One | 1 | 0 |
-----+--------+---------------+----+----+
2 | 0 | Player Two | 0 | 0 |
-----+--------+---------------+----+----+
3 | 2 | Player Three | 1 | 0 |
-----+--------+---------------+----+----+
4 | -1 | Player Four | 0 | 1 |
-----+--------+---------------+----+----+
5 | -1 | Player Five | 1 | 0 |
-----+--------+---------------+----+----+
6 | 3 | Player Six | 1 | 0 |
-----+--------+---------------+----+----+
7 | -1 | Player Seven | 0 | 1 |
-----+--------+---------------+----+----+
8 | -1 | Player Eight | 0 | 1 |
-----+--------+---------------+----+----+
9 | -1 | Player Nine | 0 | 0 |
-----+--------+---------------+----+----+
10 | 0 | Player Ten | 0 | 1 |
-----+--------+---------------+----+----+
11 | 0 | Player Eleven | 0 | 0 |
-----+--------+---------------+----+----+
12 | 0 | Player Twelve | 0 | 0 |
-----+--------+---------------+----+----+
我应该如何实现这一目标?
使用 window function ROW_NUMBER()
并按partiton by rank
划分并使用case statement
排序。
使用Row_Number
function 将具有相同排名的行分组,然后根据该行具有条件sw = 1 OR sl = 1
的事实,将值 1 包含在排序中,否则值为 0 是然后按降序排列。
事实上, Row_Number
function 根据相同的排名对行进行编号,并且在主查询中,获取编号为 1 的行。
SELECT rank,change,pseudonym,sw,sl
FROM
(SELECT *,
ROW_NUMBER() OVER(PARTITION BY rank ORDER BY CASE WHEN sw = 1 OR sl = 1 THEN 1 ELSE 0 END DESC) AS num
FROM
(SELECT
players_rankings.rank, players_rankings.change, player.pseudonym,
SUM(tot.sw) AS sw,
SUM(tot.sl) AS sl
FROM players_rankings, player, (
SELECT
player1_id AS player_id,
CASE
WHEN score1 > score2 THEN 1 ELSE 0
END AS sw,
CASE
WHEN score1 < score2 THEN 1 ELSE 0
END AS sl
FROM set WHERE edition_id = 1
UNION ALL
SELECT
player2_id,
CASE
WHEN score1 < score2 THEN 1 ELSE 0
END,
CASE
WHEN score1 > score2 THEN 1 ELSE 0
END
FROM set WHERE edition_id = 1
) AS tot
WHERE
players_rankings.edition_id = 1 AND
tot.player_id = players_rankings.player_id AND
players_rankings.player_id = player.id
GROUP BY 1, 2, 3
UNION
SELECT players_rankings.rank, players_rankings.change, player.pseudonym, 0, 0
FROM players_rankings, player
WHERE
players_rankings.edition_id = 1 AND
players_rankings.player_id = player.id) T) T
WHERE num = 1
ORDER BY 1;
db<>fiddle中的演示
警告:我还没有喝完早上的咖啡......如果我正确理解你的问题,以下(未经测试的)方法可以工作:
WITH pr AS (
SELECT players_rankings.player_id,
players_rankings.rank,
players_rankings.change,
player.pseudonym
FROM players_rankings
JOIN player
ON ( players_rankings.player_id = player.id )
WHERE players_rankings.edition_id = 1
),
tot AS (
SELECT t.player_id,
sum ( t.sw ) AS sw,
sum ( t.sl ) AS sl
FROM (
SELECT player1_id AS player_id,
CASE
WHEN score1 > score2 THEN 1
ELSE 0
END AS sw,
CASE
WHEN score1 < score2 THEN 1
ELSE 0
END AS sl
FROM SET
WHERE edition_id = 1
UNION ALL
SELECT player2_id,
CASE
WHEN score1 < score2 THEN 1
ELSE 0
END,
CASE
WHEN score1 > score2 THEN 1
ELSE 0
END
FROM SET
WHERE edition_id = 1
) AS t
GROUP BY t.player_id
)
SELECT pr.rank,
pr.change,
pr.pseudonym,
0 AS sw,
0 AS sl
FROM pr
FULL OUTER JOIN tot
ON ( pr.player_id = tot.player_id )
WHERE tot.pseudonym IS NULL
ORDER BY 1 ;
在完全外连接中编辑修复列
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.