如何通过在 python 中的同一个 psql table 中添加 2 列来获得结果

How to get results by adding 2 columns in same psql table in python

我最近开始学习数据库。现在,我正在 python 中的一个数据库支持的应用程序上测试我的技能。我在数据库中创建了 2 个这样的表

CREATE TABLE players
(
    id     SERIAL PRIMARY KEY,
    name   TEXT
);

CREATE TABLE matches 
(
    game  SERIAL,
    winner SERIAL REFERENCES players(id),
    loser SERIAL REFERENCES players(id)
);

我想查询那些获得结果的玩家 ID、名称、获胜、匹配,顺序类似于 (id、名称、获胜、匹配)。

我正在使用这段代码来做到这一点

SELECT id, name, count(matches.winner) as wins, 
 (count(matches.winner) + count(matches.loser)) as match 
  FROM players LEFT JOIN matches ON players.id = matches.winner 
  GROUP BY players.id ORDER BY wins

好像不行,请帮我解决一下。

谢谢。

我试过下面这段代码

    DB = connect()
    c = DB.cursor()
    c.execute("""WITH
                   results AS (
                            select P.id,
                                   P.name,
                                   1     win
                            from   players P inner join matches M
                            on M.winner = P.id
                            union all
                            select P.id,
                                   P.name,
                                   0    win
                            from   players P inner join matches M
                            on M.loser = P.id)
                select id,
                       name,
                       sum(win)   wins,
                       count(*)   matches
                from   results
                group by id, name """)
    return c.fetchall()
    DB.close()

此代码未从数据库中获取任何数据,而是仅返回 []。我也尝试用

替换我的查询字符串
query = oldstring.replace(" ","_")
c.execute(query)

但也没有用。请帮我解决这个问题。

首先,您可能不想对 FK 列使用 SERIAL 数据类型,因为它是一种自增整数类型,适用于 PK,但不适合 FK,最好坚持使用 INTEGER.

其次,考虑一些约束来执行我们所说的业务规则。总是有两个玩家吗?比赛没有输赢现实吗?如果以平局结束怎么办?

无论如何,让我们暂时保持简单,并假设任何时候两名玩家面对面,其中一个获胜而另一个失败。所以比赛的总数是赢 + 输。

WITH
  results AS (
    select P.id,
           P.name,
           1     win
    from   players P inner join matches M
    on M.winner = P.id
    union all
    select P.id,
           P.name,
           0    win
    from   players P inner join matches M
    on M.loser = P.id)
select id,
       name,
       sum(win)   wins,
       count(*)   matches
from   results
group by id, name

那么,这里发生了什么:

  • WITH 是一个 Common Table Expression。它基本上是一个命名子查询。我在这里使用它是为了提高可读性。我可以将子查询放在 FROM 子句中,但这样看起来好多了。
  • 您需要以某种方式加入 playersmatches,但 matches 中的每一行都引用了两名玩家。好吧,那我们就加入他们两次。
  • 当您在 matches.winner 上加入时,每场比赛都会获得一行,这一行有获胜者。这已经足够算赢了,但绝对没有输的信息。
  • 第二个查询为每场比赛增加一行,但这次这一行有失败者。
  • UNION ALL 将两个查询的结果合并到一个结果集中。
  • 但我们需要能够区分具有不同结果的行。最简单的方法是对数字求和,所以我设置 1 表示获胜,0 表示失败。
  • 最后 group 行现在使用 GROUP BY 和聚合。

您可以用类似的方式计算损失。