echo key value from a row before postgres php while loop - php

Can't believe this is giving me a problem but here it is. An example of the query and code is:
$sql = "SELECT
o.order_id, o.order_number, o.broker_id, o.agent_id
FROM orders o";
$sql_res = safe_query($sql);
/* I want to echo broker_id and angent_id only once here,
before the while loop, because the values are all the same */
while ($row = pg_fetch_array($sql_res)){
echo $order_number;
}
Assume broker and agent id numbers are each the same in every row. I don't want to echo them every time in the loop. I just want them to echo one time before the loop. Since they are the same, it does not matter which row they are echoed from.

I figured out a different way for a means to an end. It works well.
$sql = "SELECT
o.order_id, o.order_number, o.broker_id, o.agent_id
FROM orders o";
$sql_res = safe_query($sql);
$count = 0;
while ($row = pg_fetch_array($sql_res)){
if ($count == 0) {
echo $broker_id;
echo $agent_id;
}
echo $order_number;
$count += 1;
}
I realize I'm echoing the broker and agent IDs inside the while loop, but it's only an echo the first time through, and I can display them at top. And then every unique order is echoed. Visually, it accomplished what was needed for the end user.

Related

How to index a table with order by?

Using a while loop I'm able to return my table in the order I want, but after implementing pagination the variable I've created (counter) resets itself on each page, frustratingly. Example code:
$sql = ('SELECT id,name,logo FROM mytable ORDER BY name DESC LIMIT 25');
$query = mysqli_query($db_conx,$sql);
$counter = 0;
while ($row = $query->fetch_assoc()) {
$counter++;
echo "$counter, $row['id'], $row['name']";
echo "<br />";
}
I've tried many things and can't get this to work. Obviously my logic is flawed. The loop returns the correct results, but the $counter variable breaks on each page, resetting itself indefinitely.
What I am trying to do is get $counter to increase by 25 (representing results for each page) for each of the pages created by the pagination loop. Example code:
for ($i=1; $i<=$total_pages; $i++) {
echo "<a href='page.php?page=".$i."'>&nbsp[".$i."]</a> ";
$GLOBALS["counter"]+=25;
};
Obviously this was not working, so I am stumped at what I should try next. If anyone has any ideas I would love to hear them, I have heard great things about the SO community.
You seem to display only the first 25 results at any time.
You need to initialize $counter to zero if it's the first page, to 26 if it's the second page, and so on :
$counter = 0;
if(isset($_GET['counter'])){
$counter = intval($_GET['counter']);
}
You need to modify your query to fetch a different set of results for each page :
$sql = 'SELECT id,name,logo FROM mytable ORDER BY name DESC LIMIT ' . mysqli_real_escape_string($db_conx, $counter . ',25');
$query = mysqli_query($db_conx,$sql);
Then I assume you display a link to the other paginated pages, you need to pass it the value of $counter :
Next

What is my last row_number in mysql query?

I have a query like this:
$sql = "SELECT * FROM doctors WHERE city ='$city' LIMIT 10 ";
$result = $db->query($sql);
And I show the result like this :
while($row = $result->fetch_object()){
echo $row->city;
}
The Problem :
Mysql , will search through my database to find 10 rows which their city field is similar to $city.
so far it is OK;
But I want to know what is the exact row_number of the last result , which mysql selected and I echoed it ?
( I mean , consider with that query , Mysql selected 10 rows in my database
where row number are:
FIRST = 1
Second = 5
Third = 6
Forth = 7
Fifth = 40
Sixth = 41
Seventh = 42
Eitghth = 100
Ninth = 110
AND **last one = 111**
OK?
I want to know where is place of this "last one"????
)
MySQL databases do not have "row numbers". Rows in the database do not have an inherent order and thereby no "row number". If you select 10 rows from the database, then the last row's "number" is 10. If each row has a field with a primary id, then use that field as its "absolute row number".
You could let the loop run and track values. When the loop ends, you will have the last value. Like so:
while($row = $result->fetch_object()){
echo $row->city;
$last_city = $row->city;
}
/* use $last_city; */
To get the row number in the Original Table of the last resultant (here, tenth) row, you could save the data from the tenth row and then, do the following:
1. Read whole table
2. Loop through the records, checking them against the saved data
3. Break loop as soon as data found.
Like So:
while($row = $result->fetch_object()){
echo $row->city;
$last_row = $row;
}
Now, rerun the query without filters:
$sql = "SELECT * FROM doctors";
$result = $db->query($sql);
$rowNumber = 0;
while($row = $result->fetch_object()) {
if($row == $last_row) break;
$rowNumber++;
}
/* use $rowNumber */
Hope this helps.
What you can do is $last = $row->id; (or whatever field you want) inside your while loop - it will keep getting reassigned with the end result being that it contains the value of the last row.
You could do something like this:
$rowIndex = 0;
$rowCount = mysqli_num_rows($result);
You'd be starting a counter at zero and detecting the total number of records retrieved.
Then, as you step through the records, you could increment your counter.
while ( $row = $result->fetch_object() ) {
$rowIndex++;
[other code]
}
Inside the While Loop, you could check to see whether the rowIndex is equal to the rowCount, as in...
if ($rowIndex == $rowCount) {
[your code]
}
I know this is a year+ late, but I completely why Andy was asking his question. I frequently need to know this information. For instance, let's say you're using PHP to echo results in a nice HTML format. Obviously, you wouldn't need to know the record result index in the case of simply starting and ending a div, because you could start the div before the loop, and close it at the end. However, knowing where you are in the result set might affect some styling decisions (e.g., adding particular classes to the first and/or last rows).
I had one case in which I used a GROUP BY query and inserted each set of records into its own tabbed card. A user could click the tabs to display each set. I wanted to know when I was building the last tab, so that I could designate it as being selected (i.e., the one with the focus). The tab was already built by the time the loop ended, so I needed to know while inside of the loop (which was more efficient than using JavaScript to change the tab's properties after the fact).

Can't execute prepared statements using nested while loops

I am having trouble with changing over some code from old style mysql queries to being prepared. I assume the problem is due to the fact that I'm using multiple whiles which each have their own query in which is causing problems cause only one prepared statement can be active at a time.
EDIT: If anyone cares, I've made it work with only 2 loops like so -
function createDeskMenu()
{
global $bookingTimes, $dbconn;
$day0 = mktime(0, 0, 0, date("m") , date("d"), date("Y"));
$query = "SELECT location FROM location";
$result = mysqli_query($dbconn,$query);
mysqli_num_rows($result);
while ($row = mysqli_fetch_array($result))
{
$location = $row['location'];
echo "<h3>$location</h3><div>";
$query = $dbconn -> prepare("SELECT COALESCE( CountDesk, 0 ) total, name, d.desk_id, phone, fax, dock, pc FROM desk d LEFT JOIN (SELECT COUNT(booked.desk_id) CountDesk, desk_id FROM booked WHERE booking_id >=?)b ON d.desk_id = b.desk_id WHERE location=?");
$query->bind_param("is",$day0, $location);
$query->execute();
$query->bind_result($totalCount,$name,$desk_id,$phone,$fax,$dock,$pc);
while($query->fetch()) {
$total = count($bookingTimes) * 14 - $totalCount;
echo '<a href="?page=desk&desk='.$desk_id.'"><div class="desk"><b>'.$name.'
('.$total.' Available Bookings)</b><li>Facilities:';
if($phone){echo " Phone,";}if($fax){echo " Fax Machine,";}if($dock){echo " Laptop Dock.";}if($pc){echo " Desktop Workstation.";}
echo '</li></div></a><hr />';
}
$query->close();
echo '</div>';
}
}
You cannot prepare() a statement while the connection has rows waiting to be fetched from another statement. You must first either close the previous result set or fetch all rows from it.
However...
I don't see the need for the outer query which retrieves location at all, as it has no WHERE clause. You are selecting all locations, and can therefore omit that part entirely. All you are using the outer loop for is to create a <h3> for each location, and this is extremely wasteful ( in addition to originally causing you breakage in the code)
Instead, do one query and in the fetch loop, check if the location has changed. When it changes, output your header
echo "<h3>$location</h3><div>";
So remove the outer query and loop entirely, and use a pattern like the following to detect changes in location. Make sure to ORDER BY location so they are sorted for you.
No bound parameters are needed. You can do this with a query() call since the location is no longer variable and $day0 is known to be a timestamp from mktime().
// Substitute a query() call and $day0 can be inserted directly.
// This one query fetches all locations sorted...
$query = $dbconn->query("
SELECT
COALESCE( CountDesk, 0 ) total,
name,
d.desk_id,
phone,
fax,
dock,
pc
FROM
desk d
LEFT JOIN (
SELECT COUNT(booked.desk_id) CountDesk, desk_id FROM booked WHERE booking_id >= $day0
)b ON d.desk_id = b.desk_id
ORDER BY location");
// Store the last location in a variable which starts empty...
$location = "";
while($row = $query->fetch_assoc()) {
// on change of $location, update the variable.
if ($location !== $row['location']) {
$location = $row['location'];
// And output the new location value
echo "<h3>$location</h3><div>";
}
// Do the rest of your loop.
$total = count($bookingTimes) * 14 - $row['total'];
echo '<a href="?page=desk&desk='.$row['desk_id'].'"><div class="desk"><b>'.$row['name'].'
('.$total.' Available Bookings)</b><li>Facilities:';
if($row['phone']){
echo " Phone,";
}
if($row['fax']){
echo " Fax Machine,";
}
if($row['dock']){
echo " Laptop Dock.";
}
if($row['pc']){
echo " Desktop Workstation.";
}
echo '</li></div></a><hr />';
}
$row->close();
echo '</div>';
Now on to the reason it was failing.... You cannot prepare() a new statement while there are rows remaining to be fetched from a previous statement or query. You must first either fetch all the rows, or close the statement with $stmt->close(). So effectively you cannot nest fetch loops.
The better method is to first fetch all rows into an array and then loop over that array:
while ($row = $first_query->fetch()) {
// Append all onto an array
$first_query_rows[] = $row;
}
// Then loop over that
foreach ($first_query_rows as $row) {
// Do a new query with $row
}
Usually though, this can be solved with a proper JOIN.

How can I copy a database table to an array while accounting for skipped IDs?

I previously designed the website I'm working on so that I'd just query the database for the information I needed per-page, but after implementing a feature that required every cell from every table on every page (oh boy), I realized for optimization purposes I should combine it into a single large database query and throw each table into an array, thus cutting down on SQL calls.
The problem comes in where I want this array to include skipped IDs (primary key) in the database. I'll try and avoid having missing rows/IDs of course, but I won't be managing this data and I want the system to be smart enough to account for any problems like this.
My method starts off simple enough:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Two notes:
Yes, I should probably move that $localityMax check to a PHP loop.
I'm intentionally skipping the first array key.
The problem here is that any missed key in the database isn't accounted for, so it ends up outputting like this (sample table):
1 - Tok
2 - Juneau
3 - Anchorage
4 - Nashville
7 - Chattanooga
8 - Memphis
-
-
I want to write "Error" or NULL or something when the row isn't found, then continue on without interrupting things. I've found I can check if $i is less than $row[$i] to see if the row was skipped, but I'm not sure how to correct it at that point.
I can provide more information or a sample database dump if needed. I've just been stuck on this problem for hours and hours, nothing I've tried is working. I would really appreciate your assistance, and general feedback if I'm making any terrible mistakes. Thank you!
Edit: I've solved it! First, iterate through the array to set a NULL value or "Error" message. Then, in the assignations, set $i to $row["id"] right after the mysql_fetch_assoc() call. The full code looks like this:
//Run query
$localityResult = mysql_query("SELECT id,name FROM localities");
$localityMax = mysql_fetch_array(mysql_query("SELECT max(id) FROM localities"));
$localityMax = $localityMax[0];
//Reset
for ($i=1;$i<$localityMax+1;$i++)
{
$localityData["id"][$i] = NULL;
$localityData["name"][$i] = "Error";
}
//Assign table to array
for ($i=1;$i<$localityMax+1;$i++)
{
$row = mysql_fetch_assoc($localityResult);
$i = $row["id"];
$localityData["id"][$i] = $row["id"];
$localityData["name"][$i] = $row["name"];
}
//Output
for ($i=1;$i<$localityMax+1;$i++)
{
echo $i.". ";
echo $localityData["id"][$i]." - ";
echo $localityData["name"][$i];
echo "<br />\n";
}
Thanks for the help all!
Primary keys must be unique in MySQL, so you would get a maximum of one possible blank ID since MySQL would not allow duplicate data to be inserted.
If you were working with a column that is not a primary or unique key, your query would need to be the only thing that would change:
SELECT id, name FROM localities WHERE id != "";
or
SELECT id, name FROM localities WHERE NOT ISNULL(id);
EDIT: Created a new answer based on clarification from OP.
If you have a numeric sequence that you want to keep unbroken, and there may be missing rows from the database table, you can use the following (simple) code to give you what you need. Using the same method, your $i = ... could actually be set to the first ID in the sequence from the DB if you don't want to start at ID: 1.
$result = mysql_query('SELECT id, name FROM localities ORDER BY id');
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[(int) $row['id']] = array(
'id' => $row['id'],
'name' => $row['name'],
);
}
// This saves a query to the database and a second for loop.
end($data); // move the internal pointer to the end of the array
$max = key($data); // fetch the key of the item the internal pointer is set to
for ($i = 1; $i < $max + 1; $i++) {
if (!isset($data[$i])) {
$data[$i] = array(
'id' => NULL,
'name' => 'Erorr: Missing',
);
}
echo "$i. {$data[$id]['id']} - {$data[$id]['name']}<br />\n";
}
After you've gotten your $localityResult, you could put all of the id's in an array, then before you echo $localityDataStuff, check to see
if(in_array($i, $your_locality_id_array)) {
// do your echoing
} else {
// echo your not found message
}
To make $your_locality_id_array:
$locality_id_array = array();
foreach($localityResult as $locality) {
$locality_id_array[] = $locality['id'];
}

PHP List Menu Boxes - Best way to do the cycle?

This is part of code from my backoffice page. ( is an edit.php page for a user to edit / modify )
// first query to get cats from user table
$query = "select * from user where name='".$_SESSION['username']."' order by id ASC limit 1";
$result=mysql_query($query);
if (mysql_num_rows($result)) {
while($row=mysql_fetch_array($result)){
$cat1 = $row['cat1'];
$cat2 = $row['cat2'];
$cat3 = $row['cat3'];
$cat4 = $row['cat4'];
$cat5 = $row['cat5'];
$cat6 = $row['cat6'];
$cat7 = $row['cat7'];
$cat8 = $row['cat8'];
$cat9 = $row['cat9'];
$cat10 = $row['cat10'];
}
}
// now i want to build 10 select boxes with selected according the user table $cats
// below is what i can build to first box $cat1
// is there a way i can produce this for the 10 select boxes whitout having to make 10 cycles of bellow code
<select name="theme" id="theme">
<?php
$q1 = 'SELECT * FROM cats ORDER BY title ASC';
$r1 = mysql_query($q1);
while( $row = mysql_fetch_array($r1)) {
if ( $cat1 == $row['id'] ) {
print "<option class=\"cssoption\" selected=\"selected\" value=\"".$row['id']."\">".htmlentities($row['title'])."</option>";
}
else {
print "<option class=\"cssoption\" value=\"".$row['id']."\">".htmlentities($row['title'])."</option>";
}
}
?>
</select>
I am not a coder so this might not be effective code.
Hope someone can help me here and understands what i am trying to do.
Many Thanks.
The code is fine. This 10 cycles as you name it is a almost zero cost.
This is the usual way we do it, we fetch sequentialy the records one by one.
In addition it makes no sense to ask not to do the 10 cycles because you are applying an if else condition in the same time, this means that you check every record if the cat id is the same with the row so you need the loop.
On the other hand if for some reason you want to skip some records, you can use the mysql seek function to start fetching from the desired record.
for($i=0;$i<99999;$i++)
(9999*9999);
echo 'This time the cost of this loop was:',(microtime()-$start),' seconds.';
?>

Categories