高分数据库

时间:2011-10-03 20:55:20

标签: php mysql sql database-design jquery

这是一个高级/设计类型的问题,而不是任何具体的问题。

在这个游戏http://koreanwordgame.com/中,用户必须在一分钟内获得尽可能多的正确答案(尽管为了开发目的将其设置为5秒)。一分钟结束,我就用JQuery通过用户分数发起Ajax调用。

在服务器端,我使用此SQL查询获得5分以上和5分

$getquery = "(SELECT * 
FROM highscore 
WHERE score >= '$score'
ORDER BY score ASC
LIMIT 5)

UNION ALL

(SELECT * 
FROM highscore 
WHERE score < '$score'
ORDER BY score DESC
LIMIT 5)";

这会向客户端返回一个HTML表格,您将在完成(5秒)挑战时看到该表格(您无需获得任何正确答案)。

现在,我最终希望表格大约有100行(尽管它仍然只会显示周围的10个单元格,上面5个,下面5个),行位置(ID)不是按时间顺序确定的,因为它现在是通过分数,如果有人得到1000个答案,他们将直接进入数据库的第1位。显然,如果用户低于表中已存在的100行中的任何一行,则应该简单地将其丢弃。然后当表返回时,我希望文本输入显示在放置用户的表格单元格中,这样他们就可以输入他们的名字并触发另一个Ajax调用,这样他们的条目就会插入到数据库中的正确位置。

我知道要求用户首先输入他们的详细信息然后舀掉前十名的结果会更容易,无论他们是否到达那里,但我的想法是我希望任何人能够得到某种因为这将鼓励人们发挥更多。

也许是一个艰难的人......我当然无法通过谷歌搜索找到类似的东西,所有人都非常感谢!

编辑:

如果有人对此感兴趣,这就是我最终的结果,它还远没有完成我需要更加强大,例如输入匿名用户名,以防用户关闭浏览器并防止双重帖子(尽管这会是客户方)。

但是谢谢大家的帮助,没有你我不会这样做。如果你看到任何明显的改进,可以随意指出它们!

<?php

$dbcon = mysql_connect("localhost", "XXXX", "XXXX") or      die(mysql_error());
mysql_select_db("tulesblo_koreangame", $dbcon) or die(mysql_error());
mysql_query("SET NAMES utf8");

$name = $_POST["name"];
$email = $_POST["email"];
$score = $_POST["score"];
$table = "";
$submit = "";
$input = "";
$newposition = $_POST['position'];

$position = mysql_query("(SELECT position 
    FROM highscore 
   WHERE score < '$score'
ORDER BY score DESC
   LIMIT 1)");

if(!$name){

$gethigherrows = "(SELECT * 
    FROM highscore 
   WHERE score >= '$score'
ORDER BY score ASC
   LIMIT 5)";

$getlowerrows = "(SELECT * 
    FROM highscore 
   WHERE score < '$score'
ORDER BY score DESC
   LIMIT 5)";

$higherrows= mysql_query($gethigherrows);
$lowerrows= mysql_query($getlowerrows);

if(mysql_error())echo mysql_error();

while($row=mysql_fetch_array($higherrows)) 
{
    $uppertable .= "<tr><td>$row[position]</td><td>$row[name]</td>    <td>$row[score]</td></tr>";
}

$x = 0; 
if (mysql_num_rows($lowerrows) > 0)
{   mysql_query("UPDATE highscore SET position = position + 1 WHERE score <  '$score'")or die("update failed");
    while($row=mysql_fetch_array($lowerrows)) 
    {   
        if ($x == 0)
            {$position = $row['position'];};
        $x++;
        $newpos = $row[position]+1;
        $lowertable.= "<tr><td>$newpos</td><td>$row[name]</td>    <td>$row[score]</td></tr>";
    }
    $input = "<tr><td id='position'>$position</td><td><input  id='nameinput'type='text' /></td><td>$score</td></tr>";
    $submit = "<br />Enter email if you want to receive a prize!<br /><input  id='emailinput'type='text' /><br /><input id='submithighscore'type='submit'  value='Submit'>";
}

$table .= "<table id='scoretable'><tr><th>Position</th><th>Name</th><th>Score</th></tr>";
$table .= $uppertable;
$table .= $input;
$table .= $lowertable;
$table .= "</table>";
$table .= $submit;
$table .= "<br /><span class='msg'></span>";
echo $table;

}else{  echo($newposition);
mysql_query("INSERT INTO highscore VALUES (NULL, '$score', '$name', '$email',     '$newposition')");
}

?>

3 个答案:

答案 0 :(得分:3)

你没有说你的问题在哪里,但我想这主要是对SQL的误解。以下是我将如何处理整个应用程序。

对于SQL架构:

  • 您不应该关心数据库中行的顺序。您可以在查询中设置顺序(SELECT等)。插入没有“正确的位置”。
  • 出于同样的原因,您不需要“排名”列。
  • 你的表可以很简单:id(INT AUTO_INCREMENT),名称,分数,时间(时间戳)。
  • 用100个虚拟分数初始化它。

对于工作流程:

  • 现在不关心表现,以可读性为目标。
  • 正如你所写的,一旦玩家完成,使用AJAX找到10个周围的分数。您已经拥有此部分的SQL查询。您可以在PHP中在服务器端准备HTML,或者发送原始数据以便使用Javascript构建HTML。这可以在一个请求中完成(在PHP中使用json_encode()返回一个数组/对象)。
  • 如果下面没有分数,那么它不是100分中最好的分数之一,什么都不做。
  • 否则,询问用户其名称,并发送新的AJAX请求。 SQL可以保持简单:

    INSERT INTO Highscore SET name = ?, score = ?, when = NOW()

  • 每次插入后,删除最低分

    DELADE FROM Highscore ORDER BY得分ASC,当DESC LIMIT 1

  • 如果你想防止作弊,你需要在你的ajax调用中添加哈希。例如,发送(用户名,得分,散列= md5(用户名.score。“secretphrase”)并检查散列是否仍与用户名和分数匹配。

  • 如果要显示排名和分数,请在表格中添加“排名”列。插入乐谱时,将其等级设置为较低分数的最高等级(您已经为第一个AJAX请求计算了此等级,因此请在第二个AJAX请求中发送它)。然后是UPDATE Highscore SET rank = rank + 1 WHERE score < ?

答案 1 :(得分:0)

我有点理解你究竟追求的是什么。这是一个将结果插入高分的查询。

$str_user_id = $_GET['user_id'];
$str_score = $_GET['score'];

mysql_query("
INSERT INTO highscore (position, user_id, score)
SELECT (@rownum := $rownum + 1) AS position, user_id, score
FROM (SELECT user_id, score
      FROM (SELECT '{$str_user_id}' AS user_id, '{$str_score}' AS score
            UNION ALL
            SELECT user_id, score
            FROM highscore) AS h, (@rownum := 0) AS vars
      WHERE '{$str_score}' <= 100
      ORDER BY score ASC) AS h2)
LIMIT 100
ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), score = VALUES(score)
");

答案 2 :(得分:0)

我无法完全理解你的问题,但基于此:

  

“我知道要求用户首先输入他们的详细信息然后舀掉前十名的结果会更容易,无论他们是否到达那里,但我的想法是我希望任何人能够得到某种入境,因为这将鼓励人们发挥更多“

我怀疑您希望向用户显示的分数表看起来像这样:

    1. John Doe (score: 1,000,000)
    2. Larry Roe (score: 999,999)
    3. Jane Doe (score: 985,742)
 ...
 5746. Susan Player (score: 894)
 5747. *** YOU *** (score: 893)
 5748. Joe R. Player (score: 889)

我的第二个Mytskine的初步建议是你不应该尝试将排名保存在数据库中 - 保持排名列更新是可能的,就像Mytskine在答案结束时显示的那样,但这是很多工作几乎没有任何收获。只需让您的分数表包含明显的列,例如namescore以及time,再加上AUTO_INCREMENT列id

现在,假设你想要在新得分前后显示N个得分最高的球员,以及K球员。首先,我们需要弄清楚玩家的等级:

SELECT COUNT(*) + 1 FROM scores WHERE score > ?

此处,?是玩家得分的占位符。这将计算有多少玩家得分高于我们下面要插入的分数。如果我们赞成关系中的最新分数,那么加一个将是玩家的等级。让我们用R来表示这个等级。

现在,如果R&lt; N + K,我们可能只是显示最高N + 2 * K(或最大(N,R + K)或其他)条目:

SELECT * FROM scores ORDER BY score DESC, time DESC LIMIT N+2*K

否则,我们需要分三步完成:首先,获取前N个条目:

SELECT * FROM scores ORDER BY score DESC, time DESC LIMIT N

然后,玩家上方的K条目:

SELECT * FROM scores WHERE score > ? ORDER BY score ASC, time ASC LIMIT K

最后是玩家下方的K个条目:

SELECT * FROM scores WHERE score <= ? ORDER BY score DESC, time DESC LIMIT K

请注意,第二个结果集将按相反顺序排列,但这没关系 - 只需在PHP中将其反转即可。现在我们需要为我们提取的条目分配排名,但这很简单:第一组的排名为1到N,第二组(反转后)排名RK为R-1,最后一组排名为R + 1至R + K. (等级R当然属于当前的玩家。)

最后,在玩家输入他们的名字之后,我们可以简单地将玩家的分数插入数据库:

INSERT INTO scores (name, score, time) VALUES (?, ?, ?)

如果你愿意,你也可以从这个时候删除数据库中的最低分数来限制它的大小,但实际上除非你有数十亿玩家,否则它可能无关紧要。 (单个分数条目将占用几十个字节,主要取决于播放器输入的名称的长度,因此一百万个条目仍然只有几十兆字节。)但是,您应该记住创建一个索引。 (score, time)以保持查询效率。