I'm trying to make a function which will display the top X results of the row Y which I set, for this instance I'm using the row browser and the top 5 results from my table statistics, the where is just to eliminate Search Bot results from showing up. I also want it to return the count of the amount of rows as well. So say there was 10 results for the browser 'Safari', then it would return the count of 10 for that result as well as the result itself.
$display->show_list('statistics', 'browser', '5', 'WHERE browser!=\'Search Bot\'');
Here is my function. I'm cleaned it up a bit to remove certain checks and outputs if the query were to fail, etc.
function show_list($table, $row, $limit = 5, $where = NULL) {
$item = mysql_query("SELECT DISTINCT $row FROM $table $where LIMIT $limit");
$result = array();
while ($fetch = mysql_fetch_array($item)) {
$result[] = $fetch;
}
return $result;
}
Not sure I understand the question, but what about using a group by clause, in your SQL query :
select your_column, count(*)
from your_table
where ...
group by your_column
order by count(*) desc
limit 5
That would get you :
for each value of your_column,
the number of rows with that value
and you'd keep the 5 values of your_column that have the biggest number of rows
Change this line:
$item = mysql_query("SELECT $row, count(*) as rows FROM $table $where GROUP BY count(*) ORDER BY count(*) DESC LIMIT $limit");
After doing that, you may not want to mix this with your generic show_list function.
A random note. DISTINCT tends to be somewhat expensive on the database. I would avoid defaulting to doing it.
Incidentally your indentation is..interesting. No decent programmer will want to work with that code without reformatting to some consistent indentation scheme. There are endless arguments about the best way to format, but the following would be a reasonable indentation of your original code:
function show_list($table, $row, $limit = 5, $where = NULL) {
$item = mysql_query("SELECT DISTINCT $row FROM $table $where LIMIT $limit");
$result = array();
while ($fetch = mysql_fetch_array($item)) {
$result[] = $fetch;
}
return $result;
}
function show_list($table, $column, $limit = 5, $where = '') {
$item = mysql_query("SELECT $column, COUNT(*) AS c FROM $table $where
GROUP BY $column ORDER BY c LIMIT $limit");
$result = array();
while ($fetch = mysql_fetch_array($item)) {
$result[] = $fetch;
}
return $result;
}
Replace row with column - we are actually passing a column name in the variable.
Replace $where = null with $where = '' - it will ensure that the query works correctly even when $where is null.
Modify the query to generate the expected results (to the best of my understanding of your question)
Re-format the code and indent it properly.
Related
I was wondering if someone can help me with my problem that is as follows:
I want to pull once posts.text and uids which belongs to that posts.text but when I execute the code below it does this: eg. there are 4 uids that belongs to the post so I get the posts.text four times instead of once.
$query = mysqli_query($con,
"SELECT posts.text, relationships.uidb
FROM posts
LEFT JOIN relationships
ON posts.uid=relationships.uida
LIMIT 10");
if(mysqli_num_rows($query) > 0){
while($row = mysqli_fetch_assoc($query)){
echo $row['text']." ".$row['uidb']."<br>";
}
}
I would really appreciate any help.
Thanks is advance.
Peter
Update:
Desired output would be like this:
postsArray[0]->text = //post text
postsArray[1]->text = //another post text
postsArray[0]->uids[0] = //approved uid for first post
postsArray[0]->uids[1] = //another approved uid for first post
now it outputs this:
text 10
text 15
text 12
and I want this:
text 10, 15, 12
One way is to use Mysql's GROUP_CONCAT which provides comma separated values list for each group i.e (p.uid)
$query = mysqli_query($con,
"SELECT p.text, GROUP_CONCAT(r.uidb SEPARATOR ', ') uidbs
FROM posts p
LEFT JOIN relationships r
ON p.uid=r.uida
GROUP BY p.uid
LIMIT 10");
if (mysqli_num_rows($query) > 0) {
while ($row = mysqli_fetch_assoc($query)) {
echo $row['text'].' '.$row['uidbs'];
/*$uidbs= explode($row['uidbs'],',');
foreach ($uidbs as $key => $val) {
echo $val.' ';
}*/
echo '</br>';
}
}
GROUP_CONCAT
According to docs The result is truncated to the maximum length that
is given by the group_concat_max_len system variable, which has a
default value of 1024. The value can be set higher, although the
effective maximum length of the return value is constrained by the
value of max_allowed_packet.
Maybe this might work for you:
$query = mysqli_query($con,
"SELECT posts.text, relationships.uidb
FROM posts
LEFT JOIN relationships
ON posts.uid=relationships.uida
GROUP BY posts.uid
LIMIT 10");
if(mysqli_num_rows($query) > 0){
while($row = mysqli_fetch_assoc($query)){
echo $row['text']." ".$row['uidb']."<br>";
}
}
SELECT posts.text, relationships.uidb
FROM posts
LEFT JOIN relationships
ON posts.uid=relationships.uida
GROUP BY posts.primary_key_of_your_post
LIMIT 10
You should call 2 queries. In your first query, call the text, and then call uids.
You should not write complex queries because this will make your business more complex and you will not maintain your code in future.
I apologize if the title is confusing, it's hard to title this question.
I've been wondering how I could retrieve data from MySQL but only retrieve data skipping first 4 outputs where it's ordered by id.
Ex:
function firstFour()
{
$sth = $this->db->prepare("SELECT data FROM table WHERE category = 'Sports'
ORDER BY id LIMIT 4");
$sth->execute();
$row = $sth->fetch();
return $row;
}
then on the second query, skip the first four where it's ordered by id on the firstFour query above and output the rest of the data from the sports category.
You need to put limit like follows
LIMIT 4 , 4
LIMIT 8 , 4
so on
Use this query, your limit 4 is making it start from row 0 and retrieve up to row 4, setting the limit as 4, xxxx will go from 4 to whatever xxxx is. I used a large number in place of xxxx
"SELECT data FROM table WHERE category = 'Sports'
ORDER BY id LIMIT 4, 99999999999"
To expand on Zahidul's answer and to make your life easier, you might want to generalize your function a little bit - using firstFour(), secondFour(), etc. is going to make your life a lot harder. I would advise taking Zahidul's idea and passing in your limit variable:
function anyFour($lowLimit)
{
$sth = $this->db->prepare("SELECT data FROM table WHERE category = 'Sports'
ORDER BY id LIMIT $lowLimit, 4");
$sth->execute();
$row = $sth->fetch();
return $row;
}
Then if you wanted to keep the function firstFour(), it would be:
function firstFour()
{
return anyFour(0);
}
From there, you could create a simple loop that incremented by 4.
for ($x = 0; $x < 999;$x++) // 999 should be the total number of sets you want to return...
{
// on each loop, $myRows returns the next 4 rows:
$lowLimit = $x * 4;
$myRows = anyFour($lowLimit);
}
Try this:
$sth = $this->db->prepare("SELECT data FROM table WHERE category = 'Sports'
ORDER BY id;");
$sth->execute();
$row = $sth->fetch();
$row_num = 0;
while ($row) {
$row_num +=1;
if ($row_num > 4) {
//do whatever
}
}
I'm trying to use FOUND_ROWS() in my query, but the function returns wrong values sometimes.
SELECT SQL_CALC_FOUND_ROWS adminslog.*, admins.fullName FROM adminslog
JOIN admins ON admins.id=adminslog.userId ORDER BY date DESC LIMIT 0,12
In this query, I get the right value for some, but in others the limit has the wrong value.
LIMIT 0,12 164rows right
LIMIT 12,12 164rows right
LIMIT 36,12 164rows right
LIMIT 48,12 164rows right
LIMIT 50,12 60rows wrong
LIMIT 62,12 60rows wrong
Here is my class construct:
class list_table
{
public $number,$page_number,$all_rec,$table_rows,$query_str,$query,$fetch,$table,$db,$fields,$i=0,$page_n,$onclick;
function __construct($query_str,$fields,$page_n,$onclick,$page_number,$number,$db)
{
$this->fields = $fields; $this->page_number = (((int)$page_number<1)?1:(int)$page_number); $this->number = (int)$number; $this->db = $db;
$this->i = $this->page_number*$this->number-$this->number; $this->page_n = $page_n; $this->onclick = $onclick;
$this->query_str = substr(trim($query_str),0,7)."SQL_CALC_FOUND_ROWS ".substr(trim($query_str),7)." LIMIT ".(($this->page_number*$this->number)-$this->number).",".$this->number;
$this->query = $this->db->query($this->query_str);
$this->table_rows = $this->db->query("SELECT FOUND_ROWS()")->fetchColumn();
$this->all_rec = $this->query->rowCount();
$this->fetch = $this->query->fetch();
//$this->table_rows = $this->table_rows->fetch();
//$this->table_rows = $this->table_rows['cnt'];
print $this->table_rows;
}
other functions...
}
A mysql bug can be responsible for this issue, depending on which version you use:
http://bugs.mysql.com/bug.php?id=1468
You can workaround it by using a GROUP BY clause in your query.
question: you think your first FOUND_ROWS() is right every time in every query?
check that,if that is true you can run this code only in first query and save it to session.
if($this->page_number==1) $_SESSION['cr'] = $this->table_rows = $this->db->query("SELECT FOUND_ROWS()")->fetchColumn();
in this way you have not to check row counts every time.
For example I have a mysql query that gets some data. Then runs another query based some of the data that it got.
If i just return the first query, in my case $qOne. Everything works great.
BUT, after using my while loop while ($row = mysql_fetch_array($qOne)) It then returns as an empty array. (but the second query I return DOES work)
I tried to see if I could "save" the first query in another var im not messing with like this $savedResult = $qOne, then i'd just return the $savedResult but that did not work.
Does anyone know how I can get my function below to return both of the results? Thanks!
function getFoods($sort, $start, $limit) {
$qOne = mysql_query("SELECT a.id, a.name, a.type, AVG(b.r) AS fra, COUNT(b.id) as tvotes FROM `foods` a LEFT JOIN `foods_ratings` b ON a.id = b.id GROUP BY a.id ORDER BY fra DESC, tvotes DESC LIMIT $start, $limit;");
$i = 0;
$qry = "";
while ($row = mysql_fetch_array($qOne)) {
$fid = $row['id'];
if ($i > 0)
$qry .= " UNION ";
$i++;
$qry .= "SELECT fid, ing, amount FROM foods_ing WHERE fid='$fid'";
}
$qTwo = mysql_query($qry);
return array($qOne, $qTwo);
}
When you have returned the two query result resources, remember that you will need to fetch from them when you actually want to use them. (we don't see the code where you implement that).
To make use of $qOne after you already have looped through it, you must rewind it back to the first position. That is done with mysql_data_seek()
mysql_data_seek($qOne, 0);
Am try to looping through a database result set, the problem is that i know i have only one row of data, yet the loop returns 5 rows
This is my method from my model
function get_latest_pheeds() {
$data = $this->user_keywords($this->ion_auth->user_id);
$keyword = $data;
$user_id = $this->ion_auth->user_id;
foreach($keyword as $key => $word) {
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE pheed LIKE '%$word%' OR user_id='$user_id'
GROUP BY pheeds.pheed_id
ORDER BY datetime DESC";
$result = $this->db->query($q);
$rows[] = $result->result();
}
return $rows;
}
What am i doing wroing
This is because your query has an OR where it should probably have an AND - each query always matches the user_id='$user_id'.
This loop is quite inefficient anyway, I think you want to do something more like this:
function get_latest_pheeds() {
$keywords = $this->user_keywords($this->ion_auth->user_id);
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE (pheed LIKE '%".implode("%' OR pheed LIKE '%",$keywords)."%') AND user_id='".$this->ion_auth->user_id."'
GROUP BY pheeds.pheed_id
ORDER BY datetime DESC";
return $this->db->query($q);
}
If you want your results returned as an array like they were previously, you'll need to loop over results and fetch each of them into an array key of another array. I can't do it here because I can't see your db class...
EDIT: Slight fix in the above code...
ANOTHER EDIT: another fix...