as the title says i am trying to create an increasing numbers array for example:
I have a number 30 and i want to create an array out of it like
$numbers = array(6,12,18,24,30);
// then extract data from mysql
foreach( $numbers as $LIMITNUMBER ){
$query = "SELECT * FROM table WHERE id=id ORDER BY ASC LIMIT 0,".$LIMITNUMBER;
}
The 30 number above could be any number 100 or 200 but it always divides by 6 so the array first value has to be 6 and then +6 addition to the previous value.
The easiest way to do this would be to use a function implementing PHP 'range'.
Here's an example based on your question:
function incrementToMax($max) {
foreach (range(6, $max, 6) as $currentMax) {
$query = "SELECT * FROM table WHERE id=id ORDER BY ASC LIMIT 0,".$currentMax;
}
}
Example usage:
incrementToMax(60);
Related
I have a strange issue happening. I've got a table where I want to order the number of times a product was sold. I'll post the query, but the issue is inside the while loop.
Query:
$cat = $db->query("SELECT *, COUNT(id_produto) as quantos FROM produtos p JOIN pedidos m ON p.id_prod = m.id_produto GROUP BY id_produto ORDER BY quantos +0 DESC");
$cat->execute();
Now the loop:
while($res_cat = $cat->fetch(PDO::FETCH_ASSOC)){
$quantidade_ok = $res_cat['quantos'] * $res_cat['qtde'];
$quanti = array($quantidade_ok);
rsort($quanti);
foreach($quanti as $ord){
echo $ord."<br>";
}
The output is:
40
50
4
1
3
2
10
But I want it to be:
50
40
10
4
3
2
1
I'll be happy for any help.
You're sorting within a loop (so your sorting already happened), and you're sorting an array with just 1 value $quanti, so your sort does nothing.
You have 2 ways to approach this properly: edit your query to actually sort how you wish, or sort the PHP array before looping it.
Option 1: Edit your query
Based on your code it seems clear that you wish to sort by the product of quantos times qtde. So you can simply edit your query as follows:
SELECT *, COUNT(id_produto) as quantos
FROM produtos p JOIN pedidos m ON p.id_prod = m.id_produto
GROUP BY id_produto
ORDER BY (quantos*qtde) DESC
Option 2: Sort via PHP
If you prefer to sort via PHP as you don't want to change your query, you can simply populate a temporary array, the product of quantos times qtde as key and then use krsort to sort the array.
In code:
$array = [];
while ($res_cat = $cat->fetch(PDO::FETCH_ASSOC)) {
$key = $res_cat['quantos'] * $res_cat['qtde'];
$array[$key] = $res_cat;
}
krsort($array);
foreach ($array as $ord => $res_cat) {
echo $ord."<br>";
}
You overwrite $quanti each time so it always has a single value.
Try this:
$quanti = [];
while($res_cat = $cat->fetch(PDO::FETCH_ASSOC)) {
$quantidade_ok = $res_cat['quantos'] * $res_cat['qtde'];
$quanti[] = $quantidade_ok;
}
rsort($quanti);
foreach($quanti as $ord){
echo $ord."<br>";
}
I need to run an ORDER BY RAND query and then sort the resulting data set numerically. In other words I want a random set of data (in this case 7 numbers), but then I need to sort those 7 results numerically.
After this code runs:
if ($today == "Oct 31") {
$dayList = "halloween";
$stmt = $pdo->query("SELECT `rand` FROM `jukebox2014`
WHERE `class` = '$dayList' ORDER BY RAND() LIMIT 7");
}
I need to sort the 7 results.
Any ideas?
Thanks.
As simple as:
SELECT `rand`
FROM (
SELECT ... ORDER BY RAND() LIMIT 7
)
ORDER BY `rand`
Not that ORDER BY RAND() LIMIT 7 is a rather inefficient method to select random data; more efficient methods will depend on your exact data. Search Stackoverflow for many questions regarding this topic.
I think this is what you mean.
$new = array();
foreach ($results as $result) {
$new[] $result['rand'];
}
$sorted = ksort($new);
I would like get number of records in a table then divide them by 4, after dividing them by 4 i want to create sql statements with limit ranges based on my result. For example I have a table with 8 records I divide by 4, I will create 2 sql statements with a limit range like limit 0,4 and limit 4,8
Final results will look like
Select * from prop where id=123 LIMIT 0,4
Select * from prop where id=123 LIMIT 4,8
My approach was to have for loop which will count the number of sql statements to be made.
Then in the loop: first circle 0-4 and second will be 4-8
Am struggling on the limit 0-4 and limit 4-8
PHP script
include('connect.php');
$query_1 = "Select COUNT(*) as Total from prop where ref = 'SB2004'";
$results_query_1 = mysql_query($query_1);
while($row_query_1 = mysql_fetch_array($results_query_1))
{
$cnt = $row_query_1['Total'];
}
echo $cnt;
echo "<br>";
$num_grps = 0;
if ($cnt % 4 == 0 )
{
echo $num_grps = $cnt / 4 ;
}
$count_chk= $num_grps * 4;
for ($i=1;$i<=$num_grps;$i++)
{
//for loop for range
for()
{
$range = '0,4';
echo "SELECT prop_ref from prop limit".$range;
}
}
Either you've not understood the problem or haven't explained it very well.
The most immediate problem here is that you have misunderstood the syntax for the LIMIT clause. The first argument specifies the offset to start at and the second defines the number of rows to return, hence LIMIT 4,8 will return 8 rows (assuming there are 12 or more rows in the dataset).
The next issue is that you've not said if the results need to be reproducible - e.g. if you have rows with primary keys 1 and 2, should these always be returned in the same query. In the absence of an explicit ORDER BY clause, the rows will be returned based on the order in which they are found by the query.
The next issue is that you've not explained how you want to deal with the last case when the total number of rows is not an even multiple of 4.
The code you've provided counts the number of rows where ref = 'SB2004' but then creates queries which are not filtered - why?
The code you've provided does not change the limit in the queries - why?
The next issue is that there is never a good reason for running SELECT queries inside a loop like this. You didn't exlpain what you intend doing with the select queries. But based on the subsequent update....
include('connect.php');
$query_1 = "Select COUNT(*) as Total from prop where ref = 'SB2004'";
$cnt = mysql_fetch_assoc(mysql_query($query_1));
$blocks=$cnt['Total']/4 + (0 == $cnt['Total'] % 4 ? 0 : 1);
$qry2="SELECT * FROM prop where ref='SB2004' ORDER BY primary_key";
$res=mysql_fetch_assoc($qry2);
for ($x=0; $x<$blocks; $x++) {
print "<div>\n$block<br />\n";
for ($y=0; $y<4; $y++) {
print implode(",", #mysql_fetch_assoc($res)). "\n";
}
print "</div>\n";
}
It's trivial to refine this further to only issue a single query to the database.
If you really must generate individual SELECTs....
include('connect.php');
$query_1 = "Select COUNT(*) as Total from prop where ref = 'SB2004'";
$cnt = mysql_fetch_assoc(mysql_query($query_1));
$blocks=$cnt['Total']/4 + (0 == $cnt['Total'] % 4 ? 0 : 1);
for ($x=0; $x<$blocks; $x++) {
$y=$x*4;
print "SELECT * FROM prop where ref='SB2004'
ORDER BY primary_key LIMIT $y,4<br />\n"
}
I tried to achieve a method in which I create a scoreboard (while loop) and order the fetched results by a certain numeric field (points). But what I need to achieve is like the following
rank----username--point
1st------test-----------3200
2nd-----test2---------1200
etc.. I paginate my results and limit 25 results per page. I tried a while loop in the following way
while($row = mysql_fetch_array($query) || $i<=$totalnumberofrows ){
echo out the results
$i++
}
What this does is number from 1 to 25 perfectly, but on the other hand, on page 2 it numbers again from 1-25.
Is there a trick to achieve what I need to achieve?
I.e. continuous numbering from 1 to (total number of rows) even when paginated.
What you're looking for is the MySQL LIMIT statement. For example, the following query would return entry 0-24 (so, the first 25 entries in your database):
SELECT * FROM entries ORDER BY `points` LIMIT 0, 25
Say that you want to fetch the second page (the next 25 entries), you can do:
SELECT * FROM entries ORDER BY `points` LIMIT 25, 25
Most important thing to note here is that the first argument is the row where it should start, and the second argument is not the last row, but the total amount of rows it should return.
To determine the starting point, simply do (($page_number - 1) * 25), assuming your first page is numbered 1. You could for example do the following:
<?php
$start = (($page_number - 1) * 25);
$query = "SELECT * FROM entries ORDER BY `points` LIMIT {$start}, 25";
// ... rest of your code goes here ...
?>
just add 25 to the number for each page,
for the second page (in my example) - add 25
for the third page - add 50
etc...
$page = 2;
while($row = mysql_fetch_array($query) || $i<=$totalnumberofrows ){
echo out the results
echo (($page-1)*$totalnumberofrows)+$i;
$i++
}
If you know the page number and the offset you should be able to do the following
$rank = $offset * $page_number;
I want to show a random record from the database. I would like to be able to show X number of random records if I choose. Therefore I need to select the top X records from a randomly selected list of IDs
(There will never be more than 500 records involved to choose from, unless the earth dramatically increases in size. Currently there are 66 possibles.)
This function works, but how can I make it better?
/***************************************************/
/* RandomSite */
//****************/
// Returns an array of random site IDs or NULL
/***************************************************/
function RandomSite($intNumberofSites = 1) {
$arrOutput = NULL;
//open the database
GetDatabaseConnection('dev');
//inefficient
//$strSQL = "SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT ".$intNumberofSites.";";
//Not wonderfully random
//$strSQL = "SELECT id FROM site_info WHERE major <> 0 AND id >= (SELECT FLOOR( COUNT(*) * RAND()) FROM site_info ) ORDER BY id LIMIT ".$intNumberofSites.";";
//Manual selection from available pool of candidates ?? Can I do this better ??
$strSQL = "SELECT id FROM site_info WHERE major <> 0;";
if (is_numeric($intNumberofSites))
{
//excute my query
$result = #mysql_query($strSQL);
$i=-1;
//create an array I can work with ?? Can I do this better ??
while ($row = mysql_fetch_array($result, MYSQL_NUM))
{
$arrResult[$i++] = $row[0];
}
//mix them up
shuffle($arrResult);
//take the first X number of results ?? Can I do this better ??
for ($i=0;$i<$intNumberofSites;$i++)
{
$arrOutput[$i] = $arrResult[$i];
}
}
return $arrOutput;
}
UPDATE QUESTION:
I know about the ORDER BY RAND(), I just don't want to use it because there are rumors it isn't the best at scaling and performance. I am being overly critical of my code. What I have works, ORDER BY RAND() works, but can I make it better?
MORE UPDATE
There are holes in the IDs. There is not a ton of churn, but any churn that happens needs to be approved by our team, and therefore could handled to dump any caching.
Thanks for the replies!
Why not use the Rand Function in an orderby in your database query? Then you don't have to get into randomizing etc in code...
Something like (I don't know if this is legal)
Select *
from site_info
Order by Rand()
LIMIT N
where N is the number of records you want...
EDIT
Have you profiled your code vs. the query solution? I think you're just pre-optimizing here.
If you dont want to select with order by rand().
Instead of shuffeling, use array_rand on the result:
$randKeys = array_rand($arrResult, $intNumberofSites);
$arrOutput = array_intersect_key(array_flip($randKeys), $arrResult);
edit: return array of keys not new array with key => value
Well, I don't think that ORDER BY RAND() would be that slow in a table with only 66 rows, but you can look into a few different solutions anyway.
Is the data really sparse and/or updated often (so there are big gaps in the ids)?
Assuming it's not very sparse, you could select the max id from the table, use PHP's built-in random function to pick N distinct numbers between 1 and the max id, and then attempt to fetch the rows with those ids from the table. If you get back less rows than you picked numbers, get more random numbers and try again, until you have the number of rows needed. This may not be particularly fast either.
If the data is sparse, I would set up a secondary "id-type" column that you make sure is sequential. So if there are 66 rows in the table, ensure that the new column contains the values 1-66. Whenever rows are added to or removed from the table, you will have to do some work to adjust the values in this column. Then use the same technique as above, picking random IDs in PHP, but you don't have to worry about the "missing ID? retry" case.
Here are the three functions I wrote and tested
My answer
/***************************************************/
/* RandomSite1 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite1($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major <> 0;";
if (is_numeric($intNumberofSites))
{
$result = #mysql_query($strSQL);
$i=-1;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrResult[$i++] = $row[0]; }
//mix them up
shuffle($arrResult);
for ($i=0;$i<$intNumberofSites;$i++) {
$arrOutput[$i] = $arrResult[$i]; }
}
return $arrOutput;
}
JPunyon and many others
/***************************************************/
/* RandomSite2 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite2($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major<>0 ORDER BY RAND() LIMIT ".$intNumberofSites.";";
if (is_numeric($intNumberofSites))
{
$result = #mysql_query($strSQL);
$i=0;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrOutput[$i++] = $row[0]; }
}
return $arrOutput;
}
OIS with a creative solution meeting the intend of my question.
/***************************************************/
/* RandomSite3 */
//****************/
// Returns an array of random rec site IDs or NULL
/***************************************************/
function RandomSite3($intNumberofSites = 1) {
$arrOutput = NULL;
GetDatabaseConnection('dev');
$strSQL = "SELECT id FROM site_info WHERE major<>0;";
if (is_numeric($intNumberofSites))
{
$result = #mysql_query($strSQL);
$i=-1;
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$arrResult[$i++] = $row[0]; }
$randKeys = array_rand($arrResult, $intNumberofSites);
$arrOutput = array_intersect_key($randKeys, $arrResult);
}
return $arrOutput;
}
I did a simple loop of 10,000 iterations where I pulled 2 random sites. I closed and opened a new browser for each function, and cleared the cached between run. I ran the test 3 times to get a simple average.
NOTE - The third solution failed at pulling less than 2 sites as the array_rand function has different output if it returns a set or single result. I got lazy and didn't fully implement the conditional to handle that case.
1 averaged: 12.38003755 seconds
2 averaged: 12.47702177 seconds
3 averaged: 12.7124153 seconds
mysql_query("SELECT id FROM site_info WHERE major <> 0 ORDER BY RAND() LIMIT $intNumberofSites")
EDIT
Damn, JPunyon was a bit quicker :)
Try this:
SELECT
#nv := #min + (RAND() * (#max - #min)) / #lc,
(
SELECT
id
FROM site_info
FORCE INDEX (primary)
WHERE id > #nv
ORDER BY
id
LIMIT 1
),
#max,
#min := #nv,
#lc := #lc - 1
FROM
(
SELECT #min := MIN(id)
FROM site_info
) rmin,
(
SELECT #max := MAX(id)
FROM site_info
) rmax,
(
SELECT #lc := 5
) l,
site_info
LIMIT 5
This will select a random ID on each iteration using index, in descending order.
There is slight chance, though, that you get less results that you wanted, as it gives no second chance to the missed id's.
The more percent of rows you select, the bigger is the chance.
I would simply use the rand() function (I assume you are using MySQL)...
SELECT id, rand() as rand_idx FROM site_info WHERE major <> 0 ORDER BY rand_idx LIMIT x;
I'm with JPunyon. Use ORDER BY RAND() LIMIT $N. I think you'll get a bigger performance hit from $arrResult having and shuffling so many (unused) entries than from using the MySQL RAND() function.
function getSites ( $numSites = 5 ) {
// Sanitize $numSites if necessary
$result = mysql_query("SELECT id FROM site_info WHERE major <> 0 "
."ORDER BY RAND() LIMIT $numSites");
$arrResult = array();
while ( $row = mysql_fetch_array($result,MYSQL_NUM) ) {
$arrResult[] = $row;
}
return $arrResult;
}