I have a simple pdo prepared query:
$result = $db->prepare("select id, course from coursescompleted where person=:p");
$result ->bindParam(':p', $q, PDO::PARAM_INT);
$result->execute();
$rows = $result->fetch(PDO::FETCH_NUM);
echo $rows[0];
the echo seems to be returning the ID value of the record, not the number of records returned by the query?
any idea or explanation for this?
You've executed a query that returns rows from the database, fetched the first row from the result into a variable and then echo'd the first column of that row.
If you want to count, do an SQL count()
$result = $db->prepare("select count(*) from coursescompleted where person=:p");
$result->bindParam(':p', $q, PDO::PARAM_INT);
$result->execute();
$rowCount = $result->fetchColumn(0);
echo $rowCount;
PDO::FETCH_NUM: returns an array indexed by column number as returned in your result set, starting at column 0
You aren't fetching the row-count at all.
SELECT COUNT(*) FROM coursescompleted where person=:p
This query would return total rows in $rows[0];
EDIT:
Please see #ray's answer. using count(id) is better than count(*) for InnoDB.
You could get row-count in the following manner, from your earlier query.
$row_count = $result->rowCount();
But be warned:
If the last SQL statement executed by the associated PDOStatement was
a SELECT statement, some databases may return the number of rows
returned by that statement. However, this behaviour is not guaranteed
for all databases and should not be relied on for portable
applications.
Documentation
Assuming id is the primary key use:
SELECT COUNT(id) FROM coursescompleted WHERE person=:p;
Avoid a count(*). If your storage engine is InnoDB (possibly others except MyIsam) you'll take a performance hit.
Try echo count($rows); as $rows is an array.
Edit:
To use the results
$rows = $result->fetchAll(/* nothing here */);
if(count($rows) > 0) {
// Show results, perhaps using a foreach($rows as $row)
} else {
echo "Sorry, no results found";
}
You can use this
<?php
$result = $db->prepare("select id, course from coursescompleted where person=:p");
$result ->bindParam(':p', $q, PDO::PARAM_INT);
$result->execute();
$rows = $result->rowCount();
echo $rows;
?>
This sometimes does not work on SELECT queries. But based on personal experience, and since you didn't mention porting it to other database systems, it should work on MySQL.
More info is in PHP manual here
Related
So my question is:
Is it possible to select all data from different tables in one query?
Example1:
$query = $this->db->get('table1');
$query = $this->db->get('table2');
$query = $this->db->get('table3');
return $query->result();
Example2:
$this->db->select('*');
$this->db->from('table1', 'table2', 'table3');
$query = $this->db->get();
return $query->result();
I think the second exaple is possible. If not i want to ask how you would do that.
Thank you.
It can be done by putting the table names in an arrary
$query = $this->db
->select('*')
->from(['table1', 'table2'])
->get();
return $query->result();
But the number of rows in the result will be the product of the number of rows in each table, i.e. table1 has 3 rows and table2 has 19 you'll get 57 rows in the result. Are you sure that's what you want?
Joins are easy to write and highly efficient. Don't be afraid of them.
How can I get the total number of results using mysql and sphinx?
First I tried with a PDO statement, which does return a number but it is not accurate.
$array = $pdo_sphinx->prepare("select * from `my_index` where MATCH ('#name ($search)') limit $start, $limit");
$array->execute();
$query = $pdo_sphinx->prepare("select COUNT(*) from `my_index` where MATCH ('#name ($search)')");
$query->execute();
$total = $query->fetchColumn();
Then I read you can get total_found from SHOW META if you run it after the query
$array = $sphinx->Query("select * from `my_index` where MATCH ('#name ($search)') limit $start, $limit; SHOW META");
$total = $array['total_found'];
$total is returning 0, when it should be 9. How do I get the correct total_found from the query above? Is there a way to do this with the PDO statement? I need the correct result for paging
Note when you add the 'SHOW META' it makes it a multi-query. There are two separate queries, each with their own resultset.
http://php.net/manual/en/pdostatement.nextrowset.php
PDO multiple queries
(yes, using COUNT(*) may be inaccurate, because grouping can be somewhat approximate)
Is there a better way to check if there are at least two rows in a table for a given condition?
Please look at this PHP code:
$result = mysql_query("SELECT COUNT(*) FROM table WHERE .......");
$has_2_rows = (mysql_result($result, 0) >= 2);
The reason I dislike this, is because I assume MySQL will get and count ALL the matching rows, which can be slow for large results.
I would like to know if there is a way that MySQL will stop and return "1" or true when two rows are found. Would a LIMIT 2 at the end help?
Thank you.
This is a good question, and yes there is a way to make this very efficient even for large tables.
Use this query:
SELECT count(*) FROM (
SELECT 1
FROM table
WHERE .......
LIMIT 2
) x
All the work is done by the inner query, which stops when it gets 2 rows. Also note the select 1, which gives you a tiny bit more efficiency, since it doesn't have to retrieve any values from columns - just the constant 1.
The outer count(*) will count at most 2 rows.
Note: Since this is an SQL question, I've omitted PHP code from the answer.
The query below will only inspect two rows as you request. mysql_num_rows can check how many rows are returned without any looping.
$result = mysql_query("SELECT col1 FROM t1 WHERE ... LIMIT 2");
if (mysql_num_rows($result) == 2) {
Please avoid using ext/mysql and switch to PDO or mysqli if you can.
$result = mysql_query("SELECT COUNT(*) FROM table WHERE .......");
if(mysql_num_rows($result) > 1)
{
echo 'at least 2 rows';
}
else
{
echo 'less than 2 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.
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 ...