I am currently busy with creating my own 6 player game based on PHP/MySQL. I want to check if the ID from players_online is already in use, if yes then it need to keep searching until it found one (till max 6) else it need to return 0;
$con is the connection to the database and you can find the settings on the .mysql_config.php
This is what I got:
function find_local_id()
{
include'./mysql_config.php';
$i=1;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
$i++;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
$i++;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
$i++;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
$i++;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
$i++;
$select_id=mysqli_fetch_assoc(mysqli_query($con, "SELECT `ID` FROM `players_online` WHERE ID = ".$i.""));
if ($select_id["ID"] == $i) {
return 0;
} else {
return 6;
}
} else {
return 5;
}
} else {
return 4;
}
} else {
return 3;
}
} else {
return 2;
}
} else {
return 1;
}
Is there a way to have this smaller/compact? Because I think this is pretty big for just a small function. :)
I think this would work:
function find_local_id()
{
include'./mysql_config.php';
$result = mysqli_query($con, "SELECT `ID` FROM `players_online`");
while($row = mysqli_fetch_assoc($result)) {
$ids[] = $row['ID'];
}
if($available = array_diff(range(0, 6), $ids)) {
return min($available);
}
return 0;
}
If you have mysqli_fetch_all use that.
Get all of the IDs in the table
See which ones (1-6) are not in the results
If any are available return the lowest one
If not return 0
First of all, you could use a loop to do this (but you don't need one).
You're hitting the DB many times unnecessarily.
Create a function or query (like the one below) that accepts one integer id and returns the count of rows.
<?php
$db = new PDO('mysql:host=localhost;dbname=yourdb', 'user', 'pass');
$id = ''; //input, whether it be a param from a function, session superglobal, GET or POST.
$exists = $db->prepare('SELECT id FROM players_online WHERE id = ?');
$exists->execute(array($id));
echo $exists->rowCount(); // if greater than 1 or equal, it exists.
You'd be far better off doing something like
$sql = "SELECT * FROM players_online WHERE id BETWEEN {$i} AND {$i}+6";
$stmt = mysqli_query($con, $sql) or die(mysqli_error($con));
$in_use = mysqli_num_rows($stmt);
If all 6 IDs are in the database, then you'll get 6 rows in $in_use. If 5 show up, then you'll get 5 rows, etc...
You seem to have a really flawed design in that you are never going to scale for more than one game at at time with this approach, are going to need to delete rows from your table to make it work when generating a new game, and are going to have problems with race conditions in cases where concurrency is high. But assuming you have a means for managing inserting player record id's in order (1,2,3, etc.). Your query can simply be:
SELECT MAX(id) FROM players_online
This will tell you the current highest id in the table. You would simply insert the next player with the id value incremented by 1 above the current max value.
Related
I am trying to count the number of rows returned from a query
This is currently the code I have
function products()
{
$loggedin = loggedin();
$db = db();
$stmt = $db->prepare('SELECT game_id, name, developer, price FROM game WHERE quantity > 0 ORDER BY game_id DESC');
$result = $stmt->execute();
$row1 = $result->fetchArray();
$rows = count ($row1);
if ($rows == 0)
{
echo "Sold out";
}
else
{
while ($row = $result->fetchArray()) {
echo '<p>'.$row['name'].'</p>';
}
}
}
At present it will only return the first item in the table, even though all rows match
if I change my code to
function products()
{
$loggedin = loggedin();
#$page = 'index.php';
$db = db();
$stmt = $db->prepare('SELECT game_id, name, developer, price FROM game WHERE quantity > 11 ORDER BY game_id DESC');
$result = $stmt->execute();
while ($row = $result->fetchArray()) {
echo '<p>'.$row['name'].'</p>';
}
Then I get all the result from the table correctly
if I change the query to a value outside the quantity like
quantity > 20
then I get the error
Warning: count(): Parameter must be an array or an object that implements Countable
what I would like it to do is if row1 is == 0 the show sold out other wise display all the rows
so if a row does not match the query it will not be included in the results
I can not use PDO, and I have not been able to find out to use count on https://www.php.net/manual/en/book.sqlite3.php
That should do it.
function products() {
$loggedin = loggedin();
$db = db();
$games = $db->query('SELECT game_id, name, developer, price FROM game WHERE quantity > 0 ORDER BY game_id DESC');
if (empty($games->fetchArray())) {
echo "Sold out";
return;
}
// Reset the result back to the first game
$games->reset();
while ($game = $games->fetchArray(SQLITE3_ASSOC)) {
echo '<p>'.$game['name'].'</p>';
}
}
I'd do something like:
function products() {
$db = db();
$stmt = $db->prepare('SELECT game_id, name, developer, price FROM game WHERE quantity > 0 ORDER BY game_id DESC');
$result = $stmt->execute();
$count = 0;
while ($row = $result->fetchArray()) {
echo '<p>'.$row['name'].'</p>';
$count++;
}
if ($count == 0) {
echo "<p>Sold out</p>";
}
}
The only way to find out how many rows were returned by a query is to fetch all of them (and you don't actually care how many rows were returned, just that at least one was). So just increment a counter once per row returned, and after stepping through all rows, if that counter is still 0, it means no rows were returned, and you can display the relevant message.
$Prereq = "SELECT PreReqId FROM PreReq WHERE CourseId ='$CCourseId'";
$Query1= mysqli_query($db,$Prereq);
$array1 = mysqli_fetch_array($query1,MYSQLI_ASSOC);
$value= $array1['PreReqId'];
foreach($value as $i => $test)
{
$Grade = "SELECT Grade FROM Enrolled WHERE CourseId = '$test' AND UserId ='$UserId'";
$query2= mysqli_query($db,$Grade);
$array2= mysqli_fetch_array($query2,MYSQLI_ASSOC);
$value2= $array2['Grade'];
if($value2 == 'A' || $value2 == 'B' || $value2 == 'C')
{
return result = 1;
}
else
{
return result =0;
}
}
I have to check for preqrequitie grades for courses before a user can enroll in a class. As is I am able to get and echo the right prereqId. What isn't working is the grade query. Not sure why.
Though the question is rather unclear. I can suggest the following;
Your first query $Prereq only selects one value: PreReqId
You
have a typo in $Query1and than using it as mysqli_fetch_array($query1,MYSQLI_ASSOC)
It is not clear where $UserId is being set.
Try using Prepared statements to prevent Sql injections
Try the following:
$Prereq = "SELECT * FROM PreReq WHERE CourseId ='$CCourseId'";
$query1= mysqli_query($db, $Prereq);
// loop through query results
while ($row = mysqli_fetch_array($query1, MYSQLI_ASSOC))
{
// For each row perform another query
$Grade = "SELECT Grade FROM Enrolled WHERE CourseId = '".$row['PreReqId ']."' AND UserId ='$userId'";
$query2= mysqli_query($db, $Grade);
while ($row2 = mysqli_fetch_array($query2, MYSQLI_ASSOC))
{
if($row2['Grade'] == 'A' || $row2['Grade']== 'B' || $row2['Grade'] == 'C')
{
return result = 1;
}
else
{
return result =0;
}
}
}
Why not have your database perform this logic and just check if any prerequisites are missing?
function isStudentAllowedToEnroll($UserId, $CCourseId) {
$student_may_enroll = false;
// I assumed your MySQL connection is in the global scope, if not you can
// also just pass it in as another argument to the function if you'd like
global $db;
// Find all prerequisites for the course, exclude the ones the student
// has passed, then count how many are left
$query = "
SELECT COUNT(*)
FROM PreReq
LEFT JOIN Enrolled
ON Enrolled.CourseId = PreReq.PreReqId
AND Enrolled.UserId = ?
AND Enrolled.Grade IN ('A', 'B', 'C')
WHERE PreReq.CourseId = ?
AND Enrolled.CourseId IS NULL
";
if ($stmt = $db->prepare($query)) {
// I'm assuming your ids are integers, if they're strings change "ii" to "ss"
$stmt->bind_param("ii", $UserId, $CCourseId);
if ($stmt->execute()) {
$stmt->bind_result($missing_prerequisites);
$stmt->fetch();
if ($missing_prerequisites == 0) {
// No missing prerequisites, student is allowed to enroll
$student_may_enroll = true;
}
} else {
trigger_error($stmt->error, E_USER_WARNING);
}
$stmt->close();
} else {
trigger_error($db->error, E_USER_WARNING);
}
return $student_may_enroll;
}
I can understand if the query is a bit confusing. What it does is find all prerequisites for the course from the PreReq table. For each prerequisite, it tries to find a matching course in the Enrolled table for the given student with a passing grade. It then discards those matches, so in the end it counts the number of prerequisites that the student has not passed; either because the student hasn't enrolled in it or because they don't have a passing grade for it.
If the user id is an int value you should remove the single quotes.
First time tackling a project where i'm needing to pull data from one table (lets say 200 records/results), and based on the results of a certain column within that result set, i need to query one of my 5 other tables (which table i need to query isnt defined until i've made the first query)
I'm currently under the impression there is no way for me to use a JOIN of some kind to do this as i cannot know which table i need to join before the first set of results have come back.
so the solution i came up with was as follows (example code for simplicity sake)
$FirstTableVals = array();
$sql = ("SELECT * FROM TABLE_A");
$run = $con->query($sql);
if($run->num_rows > 0)
{
while($row = $run->fetch_assoc())
{
foreach($row as $key => $value)
{
$FirstTableVals[$key] = $value;
}
$valueToSwitch = $FirstTableVals["VAL_TO_SWITCH"];
//$SecondTable can be 1 of 5 different table names
$SecondTable = $FirstTableVals["SECOND_TABLE_TO_QUERY"];
switch ($valueToSwitch)
{
case"1":
$sql = ("SELECT * FROM $SecondTable WHERE SOME_COLUMN = SOME_VALUE");
$run = $con->query($sql);
if($run->num_rows > 0)
{
while($row = $run->fetch_assoc())
{
//save some values from the second table
}
}
//echo the results of TABLE_A and second table
break;
case"2":
$sql = ("SELECT * FROM $SecondTable WHERE SOME_OTHER_COLUMN = SOME_OTHER_VALUE");
$run = $con->query($sql);
if($run->num_rows > 0)
{
while($row = $run->fetch_assoc())
{
//save some values from the second table
}
}
//echo the results of TABLE_A and second table
break;
default:
break;
}
}
}
Now, the problem i'm running into is that once one of the "Second" sql queries is executed, after performing everything within the "Second" While loop, it will break out of the while loop its in and echo my values but stops there without breaking out of the switch statement and then running again, due to the "First" sql queries loop.
Essentially, this only seems to run for the first record inside of "TABLE_A" as opposed to looping again and executing the switch statement with "Second" sql queries for each record inside of "TABLE_A".
If any of this doesn't make any sense, please let me know and i'll do my best to elaborate on anything that may be confusing.
Really stumped with this one as it seems to me that should run as i've intended.
You are overridding the run variable, thats why it breaks the loop. Please change your code like this:
$FirstTableVals = array();
$sql = ("SELECT * FROM TABLE_A");
$run1 = $con->query($sql);
if($run1->num_rows > 0)
{
while($row = $run1->fetch_assoc())
{
foreach($row as $key => $value)
{
$FirstTableVals[$key] = $value;
}
$valueToSwitch = $FirstTableVals["VAL_TO_SWITCH"];
//$SecondTable can be 1 of 5 different table names
$SecondTable = $FirstTableVals["SECOND_TABLE_TO_QUERY"];
switch ($valueToSwitch)
{
case"1":
$sql = ("SELECT * FROM $SecondTable WHERE SOME_COLUMN = SOME_VALUE");
$run2 = $con->query($sql);
if($run2->num_rows > 0)
{
while($row = $run2->fetch_assoc())
{
//save some values from the second table
}
}
//echo the results of TABLE_A and second table
break;
case"2":
$sql = ("SELECT * FROM $SecondTable WHERE SOME_OTHER_COLUMN = SOME_OTHER_VALUE");
$run3 = $con->query($sql);
if($run3->num_rows > 0)
{
while($row = $run3->fetch_assoc())
{
//save some values from the second table
}
}
//echo the results of TABLE_A and second table
break;
default:
break;
}
}
}
say I have a variable
$id = mt_rand();
how can I query the mysql database to see if the variable exists in the row id, if it does exist then change the variable $id, once the variable is unique to all other stored ids, then insert it into the database?
Thanks you guys.
$con = mysql_connect("<host>","<login>","<pass>");
if ($con) {
mysql_select_db('<schemata>', $con);
$found = false;
while (!$found) {
$idIamSearching = mt_rand();
$query = mysql_query("SELECT count(*) FROM <table> WHERE <idColumnName>='".$idIamSearching."'");
$result = mysql_fetch_row($query);
if ($result[0] > 0) {
mysql_query("INSERT INTO <table> (<column>) VALUES ('".$idIamSearching."')");
$found = true;
}
}
mysql_close($con);
}
Your description is hard to understand, so, this is something that could give you pointers...
'SELECT COUNT(*) as count from table where row_id="'.$variable.'" LIMIT 1'
make sure to escape the variable if it's user input or if it's going to have more than alphanumeric characters
then fetch the row and check if count is 1 or greater than 0
if one, then it exists and try again (in a loop)
although, auto increment on the id field would allow you to avoid this step
$bExists = 0;
while(!$bExists){
// Randomly generate id variable
$result = mysql_query("SELECT * FROM table WHERE id=$id");
if($result){
if(mysql_num_rows($result) > 0){
$bExists = 1;
} else {
// Insert into database
$bExists = 1;
}
}
1 Randomly generate id variable
2 Query database for it
2.1 Result? exit
2.2 No result? Insert
I have a page that writes to a MySQL table. The table has a set amount of rows (24).
I have an $id variable that's set by a rand() function. I basically want to pull the row at that $id, so if $id was 3, I want to pull the third row. Then, I want to check if there is a price set at that row (indicating that the row is being used). If there is no price, I want to keep $id at the value it has been set at and proceed with the query. If there is a price, I want to re-randomize the $id variable, and check again if that row is used up. When it finds an empty row, proceed with the query.
My solution semi-works, but it seems to have a <10% chance of overwriting a used row, for some reason. I want it to never overwrite a used row.
Here's my code:
mysql_select_db("delives0_booklet", $con);
$query = "SELECT * FROM booklet WHERE id = '$id'";
$res = mysql_query($query,$con);
$newId = $id;
while($row = mysql_fetch_array($res))
{
if($row['price'] != 0)
{
do{
$newId = rand(1, 24);
}while($newId == $id);
}
}
$id = $newId;
mysql_query("UPDATE booklet SET price = '$price', advertiser = '$advertiser', image = '$image', monthsRemaining = '$monthsRemaining', availability = 1 WHERE id = '$id'");
Edit
I had the idea to do this. I loop through the table and I put the 'id' of each unfilled spot into an array. Then I pick randomly from that array. However, there seems to be a bug that I can't find, since the array keeps showing as having nothing in it, even after the loop is run, and $i is the correct figure.
mysql_select_db("delives0_booklet", $con);
$query = "SELECT * FROM booklet";
$res = mysql_query($query,$con);
$i = 0;
$isEmpty = array();
while($row = mysql_fetch_array($res))
{
if($row['price'] == 0)
{
$isEmpty[i] = $row['id'];
$i = $i + 1;
}
}
echo $i . " unfilled spots.";
$n = 0;
while($n<$i)
{
echo $isEmpty[$n];
$n = $n + 1;
}
if($i > 0)
{
$id = $isEmpty[rand(0, $i)];
}
if($i == 0)
{
echo 'All spots have been filled.';
}
I think it is a top level logic problem. Because you populate with random ids, you can get duplicate ids, and so when you update "WHERE id = '$id'" you may be picking up rows already populated.
I don't know your goal, but perhaps using an auto-increment id, and dropping rows that you want to get rid of, is the way to go. A rolling set of rows (24 at a time) but with ever increasing ids, would prevent mistaking one for the other.
If I understand the problem correct, this should work:
SELECT *
FROM booklet
WHERE price = 0 OR price IS NULL
ORDER BY RAND()