sqlite3数据库与python避免重复

时间:2017-12-30 17:50:56

标签: database python-3.x sqlite

  
      
  • 播放器(ID INTEGER PRIMARY KEY,姓名TEXT,性别文字,年龄整数)
  •   
  • 分数(ID INTEGER PRIMARY KEY,分数TEXT,日期DATE,时间)
  •   
  • 链接(Player_ID,Score_ID)
  •   

我有一个我正在制作的蛇游戏的数据库,如果获得高分(保存了20个最高分),程序会要求用户输入其详细信息以将其保存在此数据库中,但是如果相同的玩家达到它在数据库中重复得分很高,它有一个不同的主键。我怎样才能解决这个问题?如何从播放器表和分数表中读取数据以显示其数据。或者如果我只想显示一个玩家的分数。这就是我到目前为止所做的:

import sqlite3 
import time
import random


connection = sqlite3.connect('Test1.db')
cursor = connection.cursor()

def create_Player_Table():
    cursor.execute('CREATE TABLE IF NOT EXISTS Player (ID INTEGER PRIMARY 
     KEY, Name TEXT, Gender TEXT, Age INTEGER)')

def Insert_Player():
    ID = cursor.lastrowid
    Name = input("Enter name: ")
    Gender = input("Enter gender: ")
    Age = input("Enter age: ")
    cursor.execute("INSERT INTO Player (ID, Name, Gender, Age) VALUES (?, ?, ?, ?)",
              (ID, Name, Gender, Age))
    connection.commit()
    Player_ID = cursor.lastrowid
    return Player_ID


def create_Scores_Table():
    cursor.execute('CREATE TABLE IF NOT EXISTS Scores (ID INTEGER PRIMARY KEY, Score TEXT, Date DATE, Time TIME)')

def Insert_Score():
    ID = cursor.lastrowid
    Score = random.randint(1,100000)
    Date = time.strftime("%d/%m/%y")
    Time = time.strftime("%X")
    cursor.execute("INSERT INTO Scores (ID, Score, Date, Time) VALUES (?, ?, ?, ?)",
              (ID, Score, Date, Time))
    connection.commit()
    Score_ID = cursor.lastrowid
    return Score_ID

def create_Link_Table():
    cursor.execute('CREATE TABLE IF NOT EXISTS Link (Player_ID, Score_ID, FOREIGN KEY (Player_ID) REFERENCES Player (ID), FOREIGN KEY (Score_ID) REFERENCES Scores (ID))')

def Insert_IDs():
    cursor.execute("INSERT INTO Link (Player_ID, Score_ID) VALUES (?, ?)",(Player_ID, Score_ID))
    connection.commit()

create_Player_Table()
create_Scores_Table()
create_Link_Table()
Player_ID = Insert_Player()
Score_ID = Insert_Score()
Insert_IDs()

1 个答案:

答案 0 :(得分:0)

或许完成你想要的第一个阶段是了解如何加入表格。这个的核心是链接表。

因此,您首先从链接表中获取所有行以及链接(相关)数据。

以下表格假设如下: -

玩家表: -

enter image description here

得分表: -

enter image description here

链接表: -

enter image description here

  • 注意由于某些玩家与相同的分数相关联,这可能会稍微复杂一些。 (例如,玩家1,2和4都与得分3相关联/相关/相关,这可能不是这种情况)。

因此,以下方法可以做到这一点: -

    SELECT * FROM Link JOIN Scores ON  Score_ID = Scores.ID JOIN Player ON Player_ID = Player.id

哪会产生: -

enter image description here

我认为上面的答案

  

如何从播放器表和分数表中读取以显示它   数据

添加WHERE Player.id = 2会将结果限制为播放器2,例如

    SELECT * FROM Link JOIN Scores ON  Score_ID = Scores.ID JOIN Player ON Player_ID = Player.id WHERE Player.id = 2

我认为这回答

  

如果我只想显示一名球员的得分。

  

如果获得高分(保存20个最高分),则实现该程序   要求用户输入其详细信息以将其保存在此数据库中,但是   如果同一玩家获得高分,则在数据库中重复   它有一个不同的主键。我该如何解决这个问题?

稍微复杂一点,但首先你需要每次播放的前x个分数(为简单起见,示例使用2代表x而不是20)

您可以根据降序( DESC )顺序中的得分列对结果进行排序(排序),从而为玩家 2 获取这些内容 LIMIT 返回x的行( 2 ): -

    SELECT score FROM Link JOIN Scores ON  Score_ID = Scores.ID JOIN Player ON Player_ID = Player.id WHERE Player.id = 2 ORDER BY Score DESC LIMIT(2);

然而,你会想要最小值(如果大于此值然后加上得分),不幸的是使用SELECT MIN(得分)......将获得最低得分(对于玩家2而言不是100)预期 1100

需要复合SELECT,即SELECT MIN(得分),但仅限于播放器的前x分数(即按照之前的选择 - 因此需要选择中的选择)。这将是: -

     SELECT MIN(score) FROM (SELECT score FROM Link JOIN Scores ON  Score_ID = Scores.ID JOIN Player ON Player_ID = Player.id WHERE Player.id = 2 ORDER BY Score DESC LIMIT(2))

这导致: -

enter image description here

最后阶段是仅提取值,然后在分数大于最小值时插入新行(假设第一个最低分数是要保留的分数)。使用SELECT MIN(score) AS minscore(即添加AS minscore)将返回的行重命名为 minscore 而不是MIN(score)

可能更容易

然而,您可以更复杂地使用上述内容来提供SELECT INSERT statement的值,即它根据SELECT的结果插入数据。您甚至可以使用SQLite日期和时间函数来提供日期和时间值(假设当前时间)。

首先修改上面的日期和时间refer to - Date And Time Functions进行格式化等)

所以上面可能是: -

SELECT MIN(score) as minscore, date('now') as datenow, time('now') as timenow FROM
    (
        SELECT score FROM Link 
            JOIN Scores ON Score_ID = Scores.ID 
            JOIN Player ON Player_ID = Player.id 
            WHERE Player.id = 2 /*<<< PLAYER THIS IS FOR */
            ORDER BY Score DESC
            LIMIT(2) /*<<< Number of scores to consider */
    )

这将导致: -

enter image description here

现在需要的是将上述内容限制为仅在minscore小于分数(或分数大于minscore)时返回一行。但是,由于SQLIte确定聚合的方式,WHERE minscore&lt; ?????,必须在选择中包含上面的选择。

另一个复杂性是minscore将被视为TEXT列,因此需要SQLite CAST强制它作为整数使用。 结果是: -

SELECT * FROM (
    SELECT MIN(score) as minscore, date('now') as datenow, time('now') as timenow FROM
        (
            SELECT score FROM Link 
                JOIN Scores ON Score_ID = Scores.ID 
                JOIN Player ON Player_ID = Player.id 
                WHERE Player.id = 2 /*<<< PLAYER THIS IS FOR */
                ORDER BY Score DESC
                LIMIT(2) /*<<< Number of scores to consider */
        ) 
    )
WHERE CAST(minscore AS INT) < 100 /*<<< SCORE to add or not if too small */

几乎就在那里,这将为SELECT INSERT提供数据,最后: -

INSERT INTO Scores (Score, Date, Time) 
SELECT * FROM (
    SELECT MIN(score) as minscore, date('now') as datenow, time('now') as timenow FROM
        (
            SELECT score FROM Link 
                JOIN Scores ON Score_ID = Scores.ID 
                JOIN Player ON Player_ID = Player.id 
                WHERE Player.id = 2 /*<<< PLAYER THIS IS FOR */
                ORDER BY Score DESC
                LIMIT(2) /*<<< Number of scores to consider */
        ) 
    )
WHERE CAST(minscore AS INT) < 1200 /*<<< SCORE to add or not if too small */

请注意!然后,您将获得ID( 请注意,ID未指定为列,这是使用ID列的正常方式 )并插入条目进入Link表。 (我相信这也可以通过使用last_insert_rowid() SQLite函数来完成,但我还没有尝试过。)

P.S。很可能Link表是多余的。也许你可以将相应玩家的id存储在Scores表中(这将简化上述内容。)