繁体   English   中英

PostgresQL:查找查询中不存在的记录

[英]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.

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