I have some php file which needs to use SQL. In that SQL I get multiple results and I use here a while($stmt->fetch()){} loop inside which I need to use another SQL. Can this be accomplished or do I need to store result of the first SQL query and after closing it I can open new SQL query.
Here's code:
function compute_production($local_id, $GameID) {
global $mysqli, $M, $Q;
$sql = "SELECT `x`, `y`, `building`, `tier` FROM `GOD_battlefields` WHERE `owner`=? AND `game_id`=?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ii", $local_id, $GameID);
$stmt->execute();
$stmt->bind_result($x, $y, $BUILDING, $TIER);
while($stmt->fetch()) {
$AB_triggered = array();
fOReaCh(tech_get_value($BUILDING, "abilities") as $ability_name => $required_tier) {
if ($TIER >= $required_tier) {
switch($ability_name) {
case "auto_production":
$AB_triggered[$ability_name] = "true";
break;
case "toggle_production":
case "double_production":
// check if the order is clicked
$sql = "SELECT `post_value` FROM `GOD_cache` WHERE `post_name`=? AND `post_value` LIKE ? AND `game_id`=? AND `round`=?";
$AB_triggered[$ability_name] = "false";
$post_name = 'AbilityOrder_'.$x.'_'.$y;
$stmt2 = $mysqli->prepare($sql);
$stmt2->bind_param("ssii", $post_name, $ability_name, $GameID, $Q->game_round);
$stmt2->execute();
$stmt2->bind_result($AbilityOrder);
if ($stmt2->fetch()) {
$stmt2->close();
$AB_triggered[$ability_name] = "true";
} else {
// Keep calm and do nothing
// Everything is fine
// No action needed
// Really
}
break;
}
}
}
foreach(tech_get_value($BUILDING, "production") as $r => $value) {
if ($r == "s" || $r == "io" || $r == "w") {
// check if cell contains those resources
$multiplier = ($Q->resources_in_cell($x, $y)[$r] > $value ? 1 : 0.15);
$value *= $multiplier; // Multiply gained resources --> if mines/forests/quarries are empty, gained resources are decreased
}
$value *= tech_get_value($BUILDING, "productionm", $r) ** ($TIER - 1);
if ($AB_triggered["toggle_production"] == "true" || $AB_triggered["auto_production"] == "true") {
$RES_PER_TURN[$r] += $value;
}
}
// information about production costs
$HTML_battlefield .= "for the cost of: <br />";
foreach(resources_for_production_gen($x, $y, array($BUILDING, $TIER)) as $resource => $cost) {
if ($AB_triggered["toggle_production"] == "true" || $AB_triggered["auto_production"] == "true") {
$RES_PER_TURN[array_search($resource, $dictionary_resource)] -= $cost;
}
}
}
return $RES_PER_TURN;
}
Keeps throwing errors on the $stmt2->bind_param();
The answer is: there is no way, how to maintain multiple open queries.
Solution may be using some INNER JOIN, or other JOIN or storing the information from first SQL, close the SQL and then open the next SQL and use stored information.
Related
For part of a project i am working on in school i am building a room booking system. As part of this system, i have a page where users can enter criteria for a room and the page will return available rooms that fit that criteria and are free for booking. If a users search does not return any results i intend to lower the criteria entered, display a room that fits the altered criteria and display a message to the user informing them of the altered criteria. The call to function suggestroom() is shown here.
} else {
$reducecapacity = 1;
do {
$booking = new Booking();
$suggestedrooms = $booking->suggestroom(($capacity - $reducecapacity), $appletv, $printer);
$reducecapacity = $reducecapacity + 1;
} while($suggestedrooms === null);
echo 'This room has a cacpacity of: ' . ($capacity-($reducecapacity-1));
for($x=0; $x<count($suggestedrooms); $x++) {
echo $suggestedrooms[$x];
}
}
Public function SuggestRoom($capacity, $appletv, $printer) {
if($appletv == 1 and $printer ==0) {
$roomname = DB::GetInstance()->query("SELECT roomname FROM room WHERE capacity >= '$capacity' AND appletv ='$appletv'");
} elseif($appletv == 0 and $printer == 1) {
$roomname = DB::GetInstance()->query("SELECT roomname FROM room WHERE capacity >= '$capacity' AND printer = '$printer'");
} elseif($appletv == 1 and $printer == 1) {
$roomname = DB::GetInstance()->query("SELECT roomname FROM room WHERE capacity >= '$capacity' AND appletv ='$appletv' AND printer = '$printer'");
} else {
$roomname = DB::GetInstance()->query("SELECT roomname FROM room WHERE capacity >= '$capacity'");
}
$roomcount = $roomname->count();
if($roomcount == 0) {
echo 'No classes match your criteria';
} else {
for($x=0; $x<$roomcount; $x++) {
$RoomArray[$x] = $roomname->results()[$x]->roomname;
}
}
$LoopCount = 0;
$EndLoop = false;
$RNDnum = 0;
$availableroomcount = 0;
do {
$suggestedRoom = $RoomArray[$RNDnum];
$getRoomID = DB::GetInstance()->query("SELECT roomid FROM room WHERE roomname = '$suggestedRoom'");
$roomid = $getRoomID->results()[0]->roomid;
$bookingid = Input::get('bookingdate') . Input::get('period') . $roomid;
$CheckIfBooked = DB::GetInstance()->query("SELECT bookingid FROM booking WHERE bookingid = '$bookingid'");
if($CheckIfBooked->count() ==0) {
$availablerooms[$availableroomcount] = $suggestedRoom;
$availableroomcount = $availableroomcount+1;
}
if($LoopCount===$roomcount-1) {
$NoRoomMessage = true;
$EndLoop = true;
$suggestedRoom = null;
}
$LoopCount = $LoopCount+1;
$RNDnum = $RNDnum +1;
} while ($EndLoop <> 1);
return $availablerooms;
}
Thus, when there are no bookings, a null array will be returned to suggested rooms and this will continue until a room is found (if not, i will make it so other criteria is changed, not that far ahead yet).
A room can be found, and the code works however for x amount of times that the code is ran before a room is found i.e an empty array is returned, i get an undefined variable message. How can i get around this?
Switching off notices, warnings, errors is not the best way to code.
And unlike the above answers I prefer to always initialize a variable rather then using isset().
Use isset/empty
if(isset($var1) || !empty($var1)){
//do something
} else {
//do another
}
Before I begin, I want to point out that I can solve my problem. I've rehearsed enough in PHP to be able to get a workaround to what I'm trying to do. However I want to make it modular; without going too much into detail to further confuse my problem, I will simplify what I am trying to do so that way it does not detract from the purpose of what I'm doing. Keep that in mind.
I am developing a simple CMS to manage a user database and edit their information. It features pagination (which works), and a button to the left that you click to open up a form to edit their information and submit it to the database (which also works).
What does not work is displaying each row from MySQL in a table using a very basic script which I won't get into too much detail on how it works. But it basically does a database query with this:
SELECT * FROM users OFFSET (insert offset here) LIMIT (insert limit here)
Essentially, with pagination, it tells what number to offset, and the limit is how many users to display per page. These are set, defined, and tested to be accurate and they do work. However, I am not too familiar how to handle these results.
Here is an example query on page 2 for this CMS:
SELECT * FROM users OFFSET 10 LIMIT 10
This should return 10 rows, 10 users down in the database. And it does, when I try this command in command prompt, it gives me what I need:
But when I try to handle this data in PHP like this:
<?php
while ($row = $db->query($pagination->get_content(), "row")) {
print_r($row);
}
?>
$db->query method is:
public function query($sql, $type = "assoc") {
$this->last_query = $sql;
$result = mysql_query($sql, $this->connection);
$this->confirm_query($result);
if ($type == "row") {
return mysql_fetch_row($result);
} elseif ($type == "assoc" || true) {
return mysql_fetch_assoc($result);
} elseif ($type == "array") {
return mysql_fetch_array($result);
} elseif ($type == false) {
return $result;
}
}
$pagination->get_content method is:
public function get_content() {
global $db;
$query = $this->base_sql;
if (!isset($_GET["page"])) {
$query .= " LIMIT {$this->default_limit}";
return $query;
} elseif (isset($_GET["page"]) && $_GET["page"] == 1) {
$query .= " LIMIT {$this->default_limit}";
return $query;
} elseif (isset($_GET["page"])) {
$query .= " LIMIT {$this->default_limit}";
$query .= " OFFSET " . (($_GET["page"] * $this->default_limit) - 10);
return $query;
}
}
And my results from the while loop (which should print out each row of the database, no?) gives me the same row everytime, continuously until PHP hits the memory limit/timeout limit.
Forgive me if its something simple. I rarely ever handle database data in this manner. What I want it to do is show the 10 users I requested. Feel free to ask any questions.
AFTER SOME COMMENTS, I'VE DECIDED TO SWITCH TO MYSQLI FUNCTIONS AND IT WORKS
// performs a query, does a number of actions dependant on $type
public function query($sql, $type = false) {
$sql = $this->escape($sql);
if ($result = $this->db->query($sql)) {
if ($type == false) {
return $result;
} elseif ($type == true || "assoc") {
if ($result->num_rows >= 2) {
$array;
$i = 1;
while ($row = $result->fetch_assoc()) {
$array[$i] = $row;
$i++;
}
return $array;
} elseif ($result->num_rows == 1) {
return $result->fetch_assoc();
}
} elseif ($type == "array") {
if ($result->num_rows >= 2) {
$array;
$i = 1;
while ($row = $result->fetch_array()) {
$array[$i] = $row;
$i++;
}
return $array;
} elseif ($result->num_rows == 1) {
return $result->fetch_array();
}
}
} else {
die("There was an error running the query, throwing error: " . $this->db->error);
}
}
Basically, in short, I took my entire database, deleted it, and remade another one based on the OOD mysqli (using the class mysqli) and reformatted it into a class that extends mysqli. A better look at the full script can be found here:
http://pastebin.com/Bc00hESn
And yes, it does what I want it to. It queries multiple rows, and I can handle them however I wish using the very same methods I planned to do them in. Thank you for the help.
I think you should be using mysql_fetch_assoc():
<?php
while ($row = $db->query($pagination->get_content())) {
print_r($row);
}
?>
I have a method that can return 3 different cases
public function check_verification_status($user_id) {
global $db;
$sql = "SELECT * FROM `users`
WHERE `id` = ".clean($user_id)."
AND `type_id` = 1";
$result = #mysql_query($sql,$db); check_sql(mysql_error(), $sql, 0);
$list = mysql_fetch_array($result);
if ($list['verification_key'] == '' && !$list['verified']) {
//No key or verified
return 0;
} elseif ($list['verification_key'] != '' && !$list['verified']) {
//key exists but not verified = email sent
return 2;
} elseif ($list['verification_key'] != '' && $list['verified']) {
//verified
return 1;
}
}
A form / message is output depending on the return value from this
I would have used bool for return values when comparing 2 cases, what is the proper way of handling more than 2 cases and what would the ideal return value be.
The way i call this:
$v_status = $ver->check_verification_status($user_id);
if ($v_status === 0) {
//do something
} elseif ($v_status === 1) {
//do something else
} elseif ($v_status === 2) {
//do something totally different
}
I want to learn the right way of handling such cases as I run into them often.
note: I know I need to upgrage to mysqli or PDO, its coming soon
What you have is fine, but you can also use a switch statement:
$v_status = $ver->check_verification_status($user_id);
switch ($v_status) {
case 0: {
//do something
break;
}
case 1: {
//do something else
break;
}
case 2: {
//do something totally different
break;
}
}
So I have some code that it seems that I have to repeat over and over again for $round == P,1,2 and A. Is there any I can achieve this without producing redundant code?
I'm thinking of writing a function that simply swaps through through all 3 possible $round variables that can be available and echoing the relevant information. Any idea on how to achieve this?
The other information will remain the same - its only $round that will change,
// determine previous round
if($round == "P") echo "";
// if we are in round 1, look up round P bookings
if($round == "1")
{
$sql = "SELECT
*
FROM ts_request
INNER JOIN ts_day
ON ts_request.day_id = ts_day.id
INNER JOIN ts_period
ON ts_request.period_id = ts_period.id
INNER JOIN ts_allocation
ON ts_request.id = ts_allocation.request_id
WHERE ts_request.round=:round
AND ts_request.dept_id=:dept
ORDER BY ts_request.module_id ASC";
$stm = $pdo->prepare( $sql );
$stm->execute( array( ':round' => 'P', ':dept' => $loggedin_id ) );
$rows = $stm->fetchAll();
foreach ($rows as $row)
{
echo '<tr align="center">';
echo '<td>'.$row['module_id'].'</td>';
echo '<td>'.$row['day'].'</td>';
echo '<td>'.$row['period'].'</td>';
echo '<td>';
$sql = "SELECT * FROM ts_roompref
WHERE request_id=:id";
$stm = $pdo->prepare( $sql );
$stm->execute( array( ':id' => $row['request_id']) );
$rows2 = $stm->fetchAll();
foreach ($rows2 as $row2)
{
if ($row2['room_id']=="0")
{
echo "Any<br>";
}
else
{
echo $row2['room_id'].'<br>';
}
}
echo '</td>';
echo '<td>'.$row['status'].'</td>';
echo '</tr>';
}
}
// if we are in round 2, look up round 1 bookings
if($round == "2")
{
$sql .= "";
}
foreach ($rows as $row)
{
// echo results here
};
// if we are in round A, look up round 2 bookings
if($round == "A")
{
$sql .= "";
}
foreach ($rows as $row)
{
// echo results here
};
This may help.
$roundsInOrder = array('P', '1', '2', 'A');
$roundKey = array_search($incomingRoundLetter, $roundsInOrder);
if ($roundKey !== false || $roundKey != 0) {
$roundToQuery = $roundsInOrder[$roundKey - 1];
// your other code snipped
$stm->execute( array( ':round' => $roundToQuery, ':dept' => $loggedin_id ) );
//more code here
}
What this code does:
It sets up the rounds in order. Then, it searches the rounds for the incoming round. We really want the key. Then, the if statement checks to a) make sure we have actually found the round and b) the round is not the first one (0 = P) because we don't want to do any query then. Finally, the $roundToQuery gets the value out of the rounds that is directly before the current key.
I think what you are searching for is the switch() function in php.
Here is a nice and simple tutorial on how to use it:
http://www.tizag.com/phpT/switch.php
Hope this helps.
"Swapping" already exists, it's called "switch statement". In your case it should look like this:
switch($round) {
case "P":
//code
break;
case "1":
//code
break;
case "2":
//code
break;
case "A":
//code
break;
default:
//code, when value of $round doesn't match any case
break;
}
I am trying to execute a prepared statement with mysqli but the statement never executes with results nor throws an error. But executing the query normally work.
The prepared query looks like this:
SELECT * FROM games WHERE YEARweek(game_date)=?
The regular non prepared query is this
SELECT * FROM games WHERE YEARweek(game_date)= YEARweek(current_DATE) +1
Any ideas why?
The code for executing the query is in different places but it looks like this in short version:
$WHERE_CLAUSE='';
$first=true;
if(isset($conditions['conditions'])) {
foreach($conditions['conditions'] as $key=>$condition){
if(is_array($condition)){
} else {
if($first)
$WHERE_CLAUSE.=$key.'=?';
else
$WHERE_CLAUSE.=' AND '.$key.'=?';
$input_data[$key]=$condition;
$first=false;
}
}//end foreach
if(!empty($WHERE_CLAUSE)){
$query.='WHERE '.$WHERE_CLAUSE.' ';
}
}
$result=PVDatabase::preparedSelect($query, $input_data);
public static function preparedQuery($query, $data, $formats = '') {
if (self::_hasAdapter(get_class(), __FUNCTION__))
return self::_callAdapter(get_class(), __FUNCTION__, $query, $data, $formats);
if (self::$dbtype == self::$mySQLConnection) {
self::$link -> prepare($query);
$count = 1;
foreach ($data as $key => $value) {
self::$link -> bindParam($count, $value);
$count++;
}//end foreach
return self::$link -> execute();
} else if (self::$dbtype == self::$postgreSQLConnection) {
$result = pg_prepare(self::$link, '', $query);
$result = pg_execute(self::$link, '', $data);
return $result;
} else if (self::$dbtype == self::$oracleConnection) {
} else if (self::$dbtype == self::$msSQLConnection) {
$stmt = sqlsrv_prepare(self::$link, $query, $data);
return sqlsrv_execute($stmt);
}
}//end preparedQuery
Since you haven't provided the code you're using to invoke the query, I'm going to guess that you are probably binding a value that includes an expression. Instead of being evaluated, it'll be interpreted literally.
PDO must be escaping the YEARweek(current_DATE) +1 part of the second query.
Do this instead:
$next_year = date('Y) + 1;
SELECT * FROM games WHERE YEARweek(game_date) = $next_year