How to get only the first few matches of mysql SELECT Statement - mysql

if(strcmp($sort,"popular") == 0){
"SELECT * FROM projects WHERE project_id IN ($idResults) ORDER BY rating";
}
I first selected the projects by genres the resulting IDs are in $idResults, then i want them all sorted by rating.
It may be a very long list of results, so now my question is how can i adjust the SELECT so that I only get the first say 7 results(at the next call from 7 to 14, etc)
Thanks in advance ;)
I now tried,
$query = "SELECT * FROM projects WHERE project_id IN ".implode(',',$idResults)." ORDER BY rating LIMIT ".$count.", 7";
cause I got a php error, that there is an array to string conversion, so i added a "," after each element in the array and imploded it to a string.
but if i continue doing:
$result = $this->dbc->query($query);
$resultLines = array();
while($row = $result->fetch_array(MYSQLI_BOTH)){
$resultLines[] = $row;
}
return resultLines;
i get an error:
Fatal error: Call to a member function fetch_array() on a non-object in * on line 66
so i suspect something is still wrong in my query, but i cant figure out what.

Use the LIMIT clause - LIMIT 7.
For subsequent queries, you can use the full LIMIT clause - i.e. LIMIT offset, count. For example:
SELECT * FROM projects WHERE project_id IN ($idResults) ORDER BY rating LIMIT 0, 7;
SELECT * FROM projects WHERE project_id IN ($idResults) ORDER BY rating LIMIT 7, 7;

Related

How to save the query result in a variable and use it in another query

I want to save the last generated voucher in a variable and used as an input for another query..
$last = $this->db->query('SELECT MAX(voucherno) AS `last` FROM `purchasebill` ORDER BY no DESC LIMIT 1')->row_array();
$result = $this->db->query("SELECT * FROM `purchaseitem` where vno= '$last[0]' ORDER BY vno " )->result_array();
I tried like the above code it gives me an error undefined offset 0..Help me to save the last generated voucher no in an last variable
As per the document, $last[0] will return entire first row. In your case you want to access the value of MAX(voucherno) which is stored in an alias last.
Change $last[0] to $last['last'] in your next query and it shall work.
"SELECT * FROM `purchaseitem` WHERE vno = '{$last['last']}' ORDER BY vno"

MYSQL query needs improvement

I have a query below that produces a simple list of plants (the field named "thriller")
Problem:
Query below considers only the first sequential set of matching items from the table, then displays them in random order. The query is not considering other matching items that are found later in the table.
Solution Needed:
I want the query to choose random results from ALL items in the table, not only the first set of matching results.
$row_object = $wpdb->get_results( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}personal_creations_assistant
WHERE pot_sun_exposure = %s
AND pot_height = %s
AND pot_size = %s
AND pot_shape = %s
AND pot_placement = %s
GROUP BY thriller
ORDER BY RAND() LIMIT 0,3
",
$sun_exposure,
$height,
$size,
$shape,
$placement
)
);
If i get it right, you want to get some random rows from database. Random 3 rows.
You could do it with php. First make a COUNT to find how many rows you have total. Then say you call your variable $rowstotal; you make another one $limit_s = rand(0, $rowstotal); Then you add it to your query:
... LIMIT $limit_s, 3

How can I "order by" only the LIMIT results in a mysql Query?

Hi I need to get the results and apply the order by only in the limited section. You know, when you apply order by you are ordering all the rows, what I want is to sort only the limited section, here is an example:
// all rows
SELECT * FROM users ORDER BY name
// partial 40 rows ordered "globally"
SELECT * FROM users ORDER BY name LIMIT 200,40
The solution is:
// partial 40 rows ordered "locally"
SELECT * FROM (SELECT * FROM users LIMIT 200,40) AS T ORDER BY name
This solution works well but there is a problem: I'm working with a Listview component that needs the TOTAL rows count in the table (using SQL_CALC_FOUND_ROWS). If I use this solution I cannot get this total count, I will get the limited section count (40).
I hope you will give me solution based on the query, for example something like: "ORDER BY LOCALLY"
Since you're using PHP, might as well make things simple, right? It is possible to do this in MySQL only, but why complicate things? (Also, placing less load on the MySQL server is always a good idea)
$result = db_query_function("SELECT SQL_CALC_FOUND_ROWS * FROM `users` LIMIT 200,40");
$users = array();
while($row = db_fetch_function($result)) $users[] = $row;
usort($users,function($a,$b) {return strnatcasecmp($a['name'],$b['name']);});
$totalcount = db_fetch_function(db_query_function("SELECT FOUND_ROWS() AS `count`"));
$totalcount = $totalcount['count'];
Note that I used made-up function names, to show that this is library-agnostic ;) Sub in your chosen functions.

MySQL: what's the most efficient way to select multiple random rows

I have a fairly large dataset and a query that requires two joins, so efficiency of the query is very important to me. I need to retrieve 3 random rows from the database that meet a condition based on the result of a join. Most obvious solution is pointed out as inefficient here, because
[these solutions] need a sequential scan of all the table (because the random value associated with each row needs to be calculated - so that the smallest one can be determined), which can be quite slow for even medium sized tables.
However, the method suggested by the author there (SELECT * FROM table WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table) LIMIT 1 where num_value is ID) doesn't work for me because some IDs might be missing (because some rows may have been been deleted by users).
So, what would be the most efficient way to retrieve 3 random rows in my situation?
EDIT: the solution does not need to be pure SQL. I also use PHP.
Since you don't want many results, there are a couple of interesting options using LIMIT and OFFSET.
I'm going to assume an id column which is unique and suitable for sorting.
The first step is to execute a COUNT(id), and then select random 3 numbers from 0 to COUNT(id) - 1 in PHP. (How to do that is a separate question, and the best approach depends on the number of rows total and the number you want).
The second step has two options. Suppose the random numbers you selected are 0, 15, 2234. Either have a loop in PHP
// $offsets = array(0, 15, 2234);
foreach ($offsets as $offset) {
$rows[] = execute_sql('SELECT ... ORDER BY id LIMIT 1 OFFSET ?', $offset);
}
or build a UNION. Note: this requires sub-selects because we're using ORDER BY.
// $offsets = array(0, 15, 2234);
$query = '';
foreach ($offsets as $index => $offset) {
if ($query) $query .= ' UNION ';
$query .= 'SELECT * FROM (SELECT ... ORDER BY id LIMIT 1 OFFSET ?) Sub'.$index;
}
$rows = execute_sql($query, $offsets);
Adding your RAND() call into the ORDER BY clause should allow you to ignore the ID. Try this:
SELECT * FROM table WHERE ... ORDER BY RAND() LIMIT 3;
After having performance issues pointed out, your best bet may be something along these lines (utilizing PHP):
$result = PDO:query('SELECT MAX(id) FROM table');
$max = $result->fetchColumn();
$ids = array();
$rows = 5;
for ($i = 0; $i < $rows; $i++) {
$ids[] = rand(1, $max);
}
$ids = implode(', ', $ids);
$query = PDO::prepare('SELECT * FROM table WHERE id IN (:ids)');
$results = $query->execute(array('ids' => $ids));
At this point you should be able to select the first 3 results. The only issue with this approach is dealing with deleted rows and you might have to either bump the $rows var or add some logic to do another query in case you didn't receive at least 3 results back.

Perl MySQL - How do I return a tables last row id without looping through whole table?

my $sth = $dbh->prepare("SELECT id
FROM user
WHERE group == '1'
ORDER BY id DESC
LIMIT 1");
I was trying to get the id of the last row in a table without reading the whole table.
I am already accessing via:
my $sth = $dbh->prepare("SELECT name,
group
FROM user
WHERE group == '1'
LIMIT $from, $thismany");
$sth->execute();
while(my ($name,$group) = $sth->fetchrow_array()) {
...and setting up a little pagination query as you can see.
But, I am trying to figure out how to detect when I am on the last (<= 500) rows so I can turn off my "next 500" link. Everything else is working fine. I figured out how to turn off the "previous 500" link when on first 500 page all by myself!
I thought I would set up a "switch" in the while loop so if ($id = $last_id) I can set the "switches" var.
Like:
if ($id = $last_id) {
$lastpage = 1; #the switch
}
So I can turn off next 500 link if ($lastpage == 1).
I am really new to this and keep getting stuck on these types of things.
Thanks for any assistance.
Try to grab an extra row and see how many rows you really got. Something like this:
my #results = ( );
my $total = 0;
my $sth = $dbh->prepare(qq{
SELECT name, group
FROM user
WHERE group = ?
LIMIT ?, ?
});
$sth->execute(1, $from, $thismany + 1);
while(my ($name, $group) = $sth->fetchrow_array()) {
push(#results, [$name, $group]); # Or something more interesting.
++$total;
}
$sth->finish();
my $has_next = 0;
if($total == $thismany + 1) {
pop(#results);
$has_next = 1;
}
And BTW, please use placeholders in all of your SQL, interpolation is fraught with danger.
Always asking for one more row than you are going to show, as suggested by mu is too short, is a good way.
But if you want to take the other suggested approach of doing two separate queries, one to get the desired rows, and one to get the total count if there had not been a limit clause, MySQL provides an easy way to do that while combining as much of the work as possible:
SELECT SQL_CALC_FOUND_ROWS name, group FROM user WHERE group = '1' LIMIT ..., ...;
then:
SELECT FOUND_ROWS();
The SQL_CALC_FOUND_ROWS qualifier changes what a following FOUND_ROWS() returns without requiring you to do a whole separate SELECT COUNT(*) from user WHERE group = '1' query.
SELECT COUNT(*) from tablename will give you the number of rows, so if you keep a running count of how many rows you have read so far, you'll know when you're on the last page of results.
You could generate that query with (untested; away from a good workstation at the moment):
my $sth = $dbh->prepare("select COUNT(*) FROM user WHERE group == '1'");
my #data = $sth->fetchrow_array;
my $count = $data->[0];
(PS. you should be aware of SQL injection issues -- see here for why.)
As Ether mentioned in the comments, pagination usually requires two queries. One to return your paged set, the other to return the total number of records (using a COUNT query).
Knowing the total number of records, your current offset and the number of records in each page is enough data to work out how many pages there are in total and how many before and after the current page.
Although your initial suggestion of SELECT id FROM table WHERE ... ORDER BY id DESC LIMIT 1 should work for finding the highest matching ID, the standard way of doing this is SELECT max(id) FROM table WHERE ...