Lets say I have a table with 20 rows and a pagination script.
The pagination script is set to display 10 rows per page and of course it will display two pages.
The problem is that sometimes my table will have less than 20 rows, lets say 3 - so the script will display just one page with 3 entries.
I need a way to reppeat those 3 rows untill the number reachers 20, store them in an array, and than use the pagination script as normal.
Any ideeas, can it be done? Can someone put this in a code?
For those who wonder why?:) This is a problem becouse with each row i have asigned a post from my blog, and I have 20 posts which i want displayed. If for example the table which aoutoupdates with cron jobs has 17 rows, i'll have just 17 posts asociated with them. This is why i need to repreat them until 20, so i'll have all my 20 posts displayed no matter how many rows i have in the table:)
$query = "SELECT * FROM `db_table`";//PUT HERE A PROPER QUERY.
$result = mysql_result($query);
// mysql_num_rows($result) >10 WE ARE CHECKING HOW MANY LINES DO WE HAVE.
if(mysql_num_rows($result) >10){
/*...YOUR EXISTING CODES HERE...*/
}
else{
while($rows = mysql_fetch_assoc($result)){
$arrayOfRows[] = $rows; // HERE WE PULL ROWS FROM DB AND PUT IN AN ARRAY.
}
}
// NOW YOUR DB ROWS ARE IN THE ARRAY NAMED $arrayOfRows IF YOUR DB TABLE HAS LESS THEN 10 ROWS
$countRowsOfArray = count($arrayOfRows);
$rows = 20;
$dbRow=0;
for($n=0;$n<$rows;$n++){
if($dbRow > $countRowsOfArray) $dbRow = 0;
$newArrayOfRows[$n] = $arrayOfRows[$dbRow];
$dbRow++;
}
//NOW YOU HAVE $newArrayOfRows WHICH YOUR ROWS REPEATED UNTIL 20 LINES.
print_r($newArrayOfRows); //SEE IF THEY ARE THERE.
A simple solution would be (note: this code is optimized for readability, not speed):
$result = array();
for($i = 0; $i < 20; $i++){
$result = $array[$i % sizeof($array)];
}
This will fill the $result array with the contents of $array, repeating if necessary. You can also replace the loop condition by:
$i < 20 || $i < sizeof($array)
This will copy the whole array and, if necessary (the array has less than 20 entries), add copies.
Related
What is the best way to SELECT all from MYSQL DATABASE_1 almost every item edit (split, merge, validate email format, validate URL format, etc.) - by using php and then INSERT INTO new DATABASE 2.
The old table has almost 3 million rows.
If I do foreach for every row (which is not good idea :) ) it takes more than 1 hour for 2 thousand rows.
If I insert multiple rows in one query:
INSERT INTO tbl (col1, col2, ...) VALUES (item1, item2, ...), (item3, item4, ...)
it is almost the same
Any ideas how to do it professionally and fast?
You can do it paging the query and using several php processes. For example, a process one retrieve and edit 100000 elements the insert into new DB.
To implement it you can create a php parent process that distributes the workload into child processes, something like this:
$total_rows = //Get from your mysql table
$offsets = []
$limit = 10000;
//Create offsets to process in bulk
for ($i=0 ; $i<$total_rows ; $i++) {
$offsets[] = ($i * limit);
}
//Process rows
while ($processed_rows < $total_rows)
$pids = [];
//Create 10 childs processes
for ($i=0;$i<10;$i++) {
if ($pid) {
$pids[] = $pid;
} else {
//Get next offset to process
$offset = array_shift ($offsets);
process_and_insert_row($offset, $limit); //this function gets, edits and inserts items
}
}
//Wait for childs to finish
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
$processed_rows += $limit;
unset($pids[$pid]);
}
}
Warning: The code is not tested, but I think it demonstrates the idea behind the explanation...
The issue is not how I am generating the number, that is working fine for a different app I have. The issue is counting the total number of boxes and iterating through a forloop that many times. Right now I am multiplying box_ct * qty_ord to get the total boxes. BTW, I am still trying to understand everything I can do with foreach and for loops, so if anyone has a better idea, Great.
CLARIFICATION: I am searching the database by order number and pulling back qty_ord, box_ct, and item_no for each. On some orders there is more than one item. So for each item I need to multiply qty_ord by box_ct = count and for that specific item I need to iterate through the loop based on what my count is.Right now if I remove the foreach and hardcode the for loop count variable it works fine. Any ideas on what is wrong with my foreach?
qty_ord | box_ct | item_no
------------------------
1 2 10001
3 3 10002
2 1 10003
2 3 10004
2 6 10005
Below is my code.
$sql ="SELECT imitmidx_sql.box_ct, oeordlin_sql.item_no, oeordlin_sql.qty_ord
FROM imitmidx_sql
JOIN oeordlin_sql ON oeordlin_sql.item_no = imitmidx_sql.item_no WHERE ord_no ='$orderNum'";
$query = odbc_exec($conn, $sql);
$row7 = odbc_fetch_array($query);
foreach($row7['item_no'] as $item){
$count = $row7['qty_ord'] * $row7['box_ct'];
for($counter = 0; $counter <= $count; $counter++){
//GRAB NUMBER FROM FILE
$sscc = file_get_contents("ucc128.txt");
//INCREMENT NUMBER
$sscc++;
//PUT THE NUMBER BACK IN FILE
$sscc = file_put_contents("ucc128.txt", $sscc);
//COMBINE STATIC NUMBER AND NUMBER FROM FILE
$ssccnumber = "00950000".$sscc;
//CREATE CHECK DIGIT MATH
$ssccnumArray = str_split((string)$ssccnumber);
$ssccstep1 = array_combine(range(1, count($ssccnumArray)), $ssccnumArray);
$ssccstep2 = 0;
$ssccstep4 = 0;
foreach($ssccnumArray as $k => $v){
if($k%2){
$ssccstep2 += (int)$v;
}else{
$ssccstep4 += (int)$v;
}
}
$ssccstep3 = (int)$ssccstep2 * 3;
$ssccstep5 = (int)$ssccstep3 + (int)$step4;
$ssccCheckDigit = (ceil($ssccstep5 / 10) * 10) - $ssccstep5;
//END CREATE CHECK DIGIT
//CONCATENATE FULL NUMBER
$sscc1 = $ssccnumber.$ssccCheckDigit;
$sql = "INSERT INTO ucc128 (sscc, ord_no) VALUES ('$sscc1' ,'$orderNum')";
#echo $sql.'<br />';
odbc_exec($connPRONUMBER, $sql);
}
}
I believe your issue may be with the following:
foreach($row7['item_no'] as $item){
$count = $row7['qty_ord'] * $row7['box_ct'];
//...
}
This should be:
foreach($row7['item_no'] as $item){
$count = $item['qty_ord'] * $item['box_ct'];
//...
}
You are grabbing data from the query results, as opposed to the current row.
My foreach was not working, so what I did instead was get the sum using my SQL query.
SELECT SUM(imitmidx_sql.box_ct * oeordlin_sql.qty_ord) AS total
FROM imitmidx_sql
JOIN oeordlin_sql ON oeordlin_sql.item_no = imitmidx_sql.item_no WHERE ord_no ='$orderNum'
I was then able to ouput it and save $row7['total'] to the variable $count.
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).
I checked throught the existing topics. I have a fix for my problem but I know its not the right fix and I'm more interested making this work right, than creating a workaround it.
I have a project where I have 3 tables, diagnosis, visits, and treatments. People come in for a visit, they get a treatment, and the treatment is for a diagnosis.
For displaying this information on the page, I want to show the patient's diagnosis, then show the time they came in for a visit, that visit info can then be clicked on to show treatment info.
To do this a made this function in php:
<?
function returnTandV($dxid){
include("db.info.php");
$query = sprintf("SELECT treatments.*,visits.* FROM treatments LEFT JOIN visits ON
treatments.tid = visits.tid WHERE treatments.dxid = '%s' ORDER BY visits.dos DESC",
mysql_real_escape_string($dxid));
$result = mysql_query($query) or die("Failed because: ".mysql_error());
$num = mysql_num_rows($result);
for($i = 0; $i <= $num; ++$i) {
$v[$i] = mysql_fetch_array($result MYSQL_ASSOC);
++$i;
}
return $v;
}
?>
The function works and will display what I want which is all of the rows from both treatments and visits as 1 large assoc. array the problem is it always returns 1 less row than is actually in the database and I'm not sure why. There are 3 rows total, but msql_num_rows() will only show it as 2. My work around has been to just add 1 ($num = mysql_num_rows($result)+1;) but I would rather just have it be correct.
This section looks suspicious to me:
for($i = 0; $i <= $num; ++$i) {
$v[$i] = mysql_fetch_array($result MYSQL_ASSOC);
++$i;
}
You're incrementing i twice
You're going to $i <= $num when you most likely want $i < $num
This combination may be why you're getting unexpected results. Basically, you have three rows, but you're only asking for rows 0 and 2 (skipping row 1).
Programmers always count from 0. So, you are starting your loop at 0. If you end at 2, you have reached 3 rows.
Row0, Row1, Row2.
if $i = 0, and u increment it BEFORE adding something to the array, u skip the first row. increment $i AFTER the loop runs to start at 0 (first key).
For loops are not good for this: rather do:
$query=mysql_query(' --mysql --- ');
while ($row=mysql_fetch_array($query)){
$v[]=$row["dbcolumn"];
}
return $v for your function then.compact and neat. you can create an associative array, as long as the key name is unique (like primary ids).. $v["$priid"]=$row[1];
I need to get a random number between, lets say 1-200, but at the same time I need to prevent selecting a random number that has already been used for a particular REMOTE_ADDR (as stored in a table).
This is what I have so far (I have tried several different approaches):
$ip = $_SERVER['REMOTE_ADDR'];
$query7 = "
SELECT *
FROM IP
WHERE IP = '$ip'
";
$result7 = mysql_query($query7) or die(mysql_error());
$rows7 = mysql_num_rows($result7);
while ($row7 = mysql_fetch_array($result7)){
$id = $row7['ID'];
}
I'm using the random number to pick an image to display, but my users are complaining that the images selected for them is not random enough; ie, the same picture is getting "randomly" selected too often, sometimes showing the same image over and over.
It does not have to be in PHP, if there is another option.
Something like that
// all ids from 1 to 100
$all = array_fill(1, 200, 0);
// remove used
foreach ($used as $i) {
unset($all[$i]);
}
// get survived keys
$keys = array_keys($all);
// get random position, note that the array with keys is 0 based
$j = rand(0, count($all) - 1);
return $keys[$j];
Run your select and instead of using *, only select the id column. Then use:
while($row7[] = mysql_fetch_array($query7));
do{
$rand = rand(0,200);
}while(in_array($rand,$row7));
You can do it all in mysql. Have one table that has your list of images, and another table that has the list of IP addresses and the images that have already been shown to that IP. Then you select and join the tables and order the result randomly.
SELECT image_id FROM images
LEFT JOIN shown_images ON images.image_id=shown_images.image_id AND ip_addr=[#.#.#.#]
WHERE shown_images.image_id IS NULL
ORDER BY RAND() LIMIT 1;
After you show an image to an IP, just insert a record into the shown_images table with the IP and the image ID. That will work right up until that have seen all the images. Then you can delete the records and start over.
This answer assumes that you have 200 items, and collect the items which you do not want to show. Alternatively, you can query only id's of available items and choose from these, you would need to create a table with available items for that.
Create a map which maps consecutive numbers to (non-consecutive) available numbers. Suppose the numbers 1 and 3 are in use, you can map to 2 and 4 (and so on).
Actually, it is possible to use a simple array (not-associative) for this. You can do something like this:
$reserved = array(1, 3); // fill $reserved using your code
$available = array();
for ($i = 1; $i <= 200; $i++) {
if (!in_array($i, $reserved)) {
$available[] = $i;
}
}
if (count($available) > 0) {
$random_index = rand(0, count($available) - 1);
$r = $available[$random_index];
} else {
// Nothing available!
}
There will be nothing to choose when you run out of pictures that have not been displayed yet. In this case, count($available) will be zero. One way to solve this would be to clear your list of displayed images for the current IP and choose again; see also other answers for this.