我的问题几乎是自我解释,但我不能努力使其尽可能高效 我想从MySQL数据库中选择一个随机条目。我希望它尽可能快,尽可能高效(这始终是目标,不是吗?)。当我选择那行时,我想选择另一行,但与之前的行不同。如果我选择10行,我希望第11行与其他行不同(让我们说独特:))。但是当我用完行时,我想“报告错误”。
了解问题的核心。我正在使用PHP与MySQL。我有一个包含已经选择的标题的输入数组。然后我得到数据库中所有项目的计数,所以我知道我可以“循环最多”多少次。让我们粘贴代码,看看我们在这里处理的是什么。
try
{
$db = new PDO("mysql:host=localhost;dbname=xxxxx;charset=utf8", "xxxx", "xxxx");
$played = explode(":;:", $_POST['items']); //All already selected items are in $_POST separated by :;:
$sql = "SELECT count(id) AS count FROM table"; //Lets get the total count of items
$query = $db->prepare($sql);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
$count = $result['count']; //There we are...
$i = 0; //Index counter so we dont exceed records.. well kinda (more on that below)
do //do while because we want something to be selected first
{
$sql = "SELECT FLOOR(RAND() * COUNT(*)) AS offset FROM table"; //From here
$query = $db->prepare($sql);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
$offset = $result['offset'];
$sql = "SELECT itemXML FROM table LIMIT $offset, 1";
$query = $db->prepare($sql);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC); //To here is some code to randomly select a record "as efficiently as possible"..
$output = Array();
$xml = simplexml_load_string($result['itemXML']);
$i++;
} while (in_array($xml->{"title"}, $played) && $i < $count); //While record title is in array and while we have not exceeded the total number of records (that's the logic but it isint that simple is it?)
if ($i >= $count)
{
die("400"); //Just a random status code which I parse with the client.
}
$itemArr = Array("whatever" => $xml->{"whatever-attr"}, "title" => $xml->{"title"});
array_push($output, $itemArr); Lets push this to out array
echo json_encode($output); //Aaaaand finally lets print out the results
}
catch (Exception $e) //If anything went wrong lets notify our client so he can respond properly
{
$output = Array("error" => $e->getMessage());
die(json_encode($output));
}
是的..问题是,如果有10条记录,则选择了9行,索引计数器$i
变大或等于10,随机记录全部在数组中。那么我们应该选择一行,但不是。
我该如何解决这个问题?非常感谢您的帮助! 如果我没有充分解释它让我知道我会更加努力。
答案 0 :(得分:2)
我认为你在这里采取了错误的做法。您不需要在数据库中循环查询一次一条记录。
如果您需要选择10条记录,只需选择由RAND()订购的10条记录,如此
SELECT * FROM table
ORDER BY RAND()
LIMIT 10;
或者,如果您要从选择中省略某些ID
SELECT * FROM table
WHERE id NOT IN (?, ?, ?, ...)
ORDER BY RAND()
LIMIT 10;
或者,如果您要省略的ID存储在另一个表
中SELECT * FROM table
LEFT OUTER JOIN omit_table ON table.id = omit_table.id
WHERE omit_table.id IS NULL
ORDER BY RAND()
LIMIT 10;
答案 1 :(得分:1)
假设您已经在下表中填充了数据:
TABLE mydata
id INT AUTOINCREMENT PRIMARYKEY
name VARCAHAR
...
我们为一些非真正随机的映射创建了下表:
TABLE shufflemap
id INT AUTOINCREMENT PRIMARYKEY
data_id INT UNIQUEINDEX
我们执行以下操作:
$rs = $dbh->query('SELECT id FROM mydata');
shuffle($rs);
foreach($rs as $data_id) {
$dbh->query('INSERT INTO shufflemap (data_id) VALUES (?)', array($data_id));
}
现在如果我们要添加行怎么办?您可以TRUNCATE
表格并重新运行上述代码,或者:
$my_new_id = 1234; //the ID of the new row inserted into `mydata`
$rs = $dbh->query('SELECT COUNT(*) AS 'count' from shufflemap');
$target = rand(0,$rs[0]['count']);
$rs = $dbh->query('SELECT id, data_id FROM shufflemap LIMIT ?,1', array($target));
$swap_id = $rs[0]['id'];
$swap_data_id = $rs[0]['data_id'];
$dbh->query('UPDATE shufflemap SET data_id = ? WHERE id = ?', array($my_new_id, $swap_id));
$dbh->query('INSERT INTO shufflemap (data_id) VALUES (?)', array($swap_data_id));
以合理有效的方式从shufflemap表中选择随机条目,将data_id替换为新的,并将旧版本添加到表的末尾。
使用这种方式,您可以使用看似随机的数据而不重复,并且仍然可以通过使用JOIN,子查询或其他任何其他内容中的shufflemap表来使用表中的所有正确索引。 / p>
假设mydata表有一个字段,指示每个字段与哪个客户或用户相关联,即:
TABLE mydata
id INT AUTOINCREMENT PRIMARYKEY
client_id INT
name VARCAHAR
...
可以通过以下方式检索仅客户端数据的混洗列表:
SELECT d.*
FROM mydata d INNER JOIN shufflemap s
ON d.id = s.data_id
WHERE client_id = ?
ORDER BY s.id
排除已经播放的项目列表?
SELECT d.*
FROM mydata d INNER JOIN shufflemap s
ON d.id = s.data_id
WHERE client_id = ?
AND d.id NOT IN(?,?,?,...)
ORDER BY s.id