Hi need to count all rows in two MySQL tables.
Tables have same structure and the code I'm using in the model file is the following:
$this->regs_db->select ("*");
$this->regs_db->from("$this->table_images_civil, $this->table_images_military");
return $this->regs_db->count_all_results();
The result I'm getting is not correct at all. I know that in the first table there are 10,934 rows, in the second one there are 1,299 rows...but the result I get is 14,203,266.
What's wrong with the code above?
Thanks a lot for any hint.
EDIT: below table strusture...same for both tables
First, I'd drop Code Igniter's DB methods. They're (in my view) obstructive and useless for anything except basic query structures.
With that in mind, you can achieve what you want with something like this:
$sql = '
SELECT
(SELECT COUNT(id) FROM `'.$this->table_images_civil.'`) AS tbl1Count,
(SELECT COUNT(id) FROM `'.$this->table_images_military.'`) AS tbl2Count';
$request = $this->regs_db->query($sql);
$arr = $request->fetch_assoc();
$this->db->from('yourtable');
[... more active record code ...]
$query = $this->db->get();
$rowcount = $query->num_rows();
Getting the Value:
I've got the levenshtein_ratio function, from here, queued up in my MySQL database. I run it in the following way:
$stmt = $db->prepare("SELECT r_id, val FROM table WHERE levenshtein_ratio(:input, someval) > 70");
$stmt->execute(array('input' => $input));
$result = $stmt->fetchAll();
if(count($result)) {
foreach($result as $row) {
$out .= $row['r_id'] . ', ' . $row['val'];
}
}
And it works a treat, exactly as expected. But I was wondering, is there a nice way to also get the value that levenshtein_ratio() calculates?
I've tried:
$stmt = $db->prepare("SELECT levenshtein_ratio(:input, someval), r_id, val FROM table WHERE levenshtein_ratio(:input, someval) > 70");
$stmt->execute(array('input' => $input));
$result = $stmt->fetchAll();
if(count($result)) {
foreach($result as $row) {
$out .= $row['r_id'] . ', ' . $row['val'] . ', ' . $row[0];
}
}
and it does technically work (I get the percentage from the $row[0]), but the query is a bit ugly, and I can't use a proper key to get the value, like I can for the other two items.
Is there a way to somehow get a nice reference for it?
I tried:
$stmt = $db->prepare("SELECT r_id, val SET output=levenshtein_ratio(:input, someval) FROM table WHERE levenshtein_ratio(:input, someval) > 70");
modelling it after something I found online, but it didn't work, and ends up ruining the whole query.
Speeding It Up:
I'm running this query for an array of values:
foreach($parent as $input){
$stmt = ...
$stmt->execute...
$result = $stmt->fetchAll();
... etc
}
But it ends up being remarkably slow. Like 20s slow, for an array of only 14 inputs and a DB with about 350 rows, which is expected to be in the 10,000's soon. I know that putting queries inside loops is naughty business, but I'm not sure how else to get around it.
EDIT 1
When I use
$stmt = $db->prepare("SELECT r_id, val SET output=levenshtein_ratio(:input, someval) FROM table WHERE levenshtein_ratio(:input, someval) > 70");
surely that's costing twice the time as if I only calculated it once? Similar to having $i < sizeof($arr); in a for loop?
To clean up the column names you can use "as" to rename the column of the function. At the same time you can speed things up by using that column name in your where clause so the function is only executed once.
$stmt = $db->prepare("SELECT r_id, levenshtein_ratio(:input, someval) AS val FROM table HAVING val > 70");
If it is still too slow you might consider a c library like https://github.com/juanmirocks/Levenshtein-MySQL-UDF
doh - forgot to switch "where" to "having", as spencer7593 noted.
I'm assuming that `someval` is an unqalified reference to a column in the table. While you may understand that without looking at the table definition, someone else reading the SQL statement can't tell. As an aid to future readers, consider qualifying your column references with the name of the table or (preferably) a short alias assigned to the table in the statement.
SELECT t.r_id
, t.val
FROM `table` t
WHERE levenshtein_ratio(:input, t.someval) > 70
That function in the WHERE clause has to be evaluated for every row in the table. There's no way to get MySQL to build an index on that. So there's no way to get MySQL to perform an index range scan operation.
It might be possible to get MySQL to use an index for the query, for example, if the query had an ORDER BY t.val clause, or if there is a "covering index" available.
But that doesn't get around the issue of needing to evaluate the function for every row. (If the query had other predicates that excluded rows, then the function wouldn't necessarily need be evaluated for the excluded rows.)
Adding the expression to the SELECT list really shouldn't be too expensive if the function is declared to be DETERMINISTIC. A second call to a DETERMINISTIC function with the same arguments can reuse the value returned for the previous execution. (Declaring a function DETERMINISTIC essentially means that the function is guaranteed to return the same result when given the same argument values. Repeated calls will return the same value. That is, the return value depends only the argument values, and doesn't depend on anything else.
SELECT t.r_id
, t.val
, levenshtein_ratio(:input, t.someval) AS lev_ratio
FROM `table` t
WHERE levenshtein_ratio(:input2, t.someval) > 70
(Note: I used a distinct bind placeholder name for the second reference because PDO doesn't handle "duplicate" bind placeholder names as we'd expect. (It's possible that this has been corrected in more recent versions of PDO. The first "fix" for the issue was an update to the documentation noting that bind placeholder names should appear only once in statement, if you needed two references to the same value, use two different placeholder names and bind the same value to both.)
If you don't want to repeat the expression, you could move the condition from the WHERE clause to the HAVING, and refer to the expression in the SELECT list by the alias assigned to the column.
SELECT t.r_id
, t.val
, levenshtein_ratio(:input, t.someval) AS lev_ratio
FROM `table` t
HAVING lev_ratio > 70
The big difference between WHERE and HAVING is that the predicates in the WHERE clause are evaluated when the rows are accessed. The HAVING clause is evaluated much later, after the rows have been accessed. (That's a brief explanation of why the HAVING clause can reference columns in the SELECT list by their alias, but the WHERE clause can't do that.)
If that's a large table, and a large number of rows are being excluded, there might be a significant performance difference using the HAVING clause.. there may be a much larger intermediate set created.
To get an "index used" for the query, a covering index is the only option I see.
ON `table` (r_id, val, someval)
With that, MySQL can satisfy the query from the index, without needing to lookup pages in the underlying table. All of the column values the query needs are available from the index.
FOLLOWUP
To get an index created, we would need to create a column, e.g.
lev_ratio_foo FLOAT
and pre-populate with the result from the function
UPDATE `table` t
SET t.lev_ratio_foo = levenshtein_ratio('foo', t.someval)
;
Then we could create an index, e.g.
... ON `table` (lev_ratio_foo, val, r_id)
And re-write the query
SELECT t.r_id
, t.val
, t.lev_ratio_foo
FROM `table` t
WHERE t.lev_ratio_foo > 70
With that query, MySQL can make use of an index range scan operation on an index with lev_ratio_foo as the leading column.
Likely, we would want to add BEFORE INSERT and BEFORE UPDATE triggers to maintain the value, when a new row is added to the table, or the value of the someval column is modified.
That pattern could be extended, additional columns could be added for values other than 'foo'. e.g. 'bar'
UPDATE `table` t
SET t.lev_ratio_bar = levenshtein_ratio('bar', t.someval)
Obviously that approach isn't going to be scalable for a broad range of input values.
Hi there i am working on PHP code that is selecting columns from two tables.
Here is my code:
$result2 = mysql_query("SELECT *
FROM `videos`, `m_subedvids`
WHERE `videos.approved`='yes' AND
`videos.user_id`='$subedFOR'
ORDER BY `videos.indexer`
DESC LIMIT $newVID");
while($row2 = mysql_fetch_array($result2))
{
$indexer = addslashes($row2['videos.indexer']);
$title_seo = addslashes($row2['videos.title_seo']);
$video_id = addslashes($row2['videos.video_id']);
$title = addslashes($row2['videos.title']);
$number_of_views = addslashes($row2['videos.number_of_views']);
$video_length = addslashes($row2['videos.video_length']);
}
When i try to print $indexer with echo $indexer; it's not giving me any results.
Where is my mistake in this code?
It seems to me like the key 'indexer' isn't in your results. It's hard to tell, since you haven't listed a definition for your table and you're using SELECT * so we can't see the names.
It makes the program easier to read later, if instead of SELECT *..., you use SELECT col1, col2, .... Yes, SELECT * will save you some typing right now, but you'll lose that time later when you or anyone else who works on your code has to check the table definition every time they work with that line of code.
So, try changing your query to explicitly select the columns you use. If it's an invalid column you'll get an error right away rather than this silent failure you're getting now, and you'll thank yourself later as well.
So long as videos.indexer is a unique field name among all tables used in the query you can change
$indexer = addslashes($row2['videos.indexer']);
to
$indexer = addslashes($row2['indexer']);
You don't need to (or can not) use the table name when referring to the result.
I have my SQL statement like this trying to get the difference in 2 timestamps greater than 10 minutes. "timestamp" is a column in MYSQL which I hold a timstamp as such "1365793346"
SELECT * FROM table WHERE TIMESTAMPDIFF(MINUTE,timestamp,NOW()) AS thisisit
Im not sure if using "AS thisisit" is a current function of TIMESTAMPDIFF but I was able to find some old posts that how it used as such. I am not sure if its supported anymore because I an a syntax error at "AS thisisit"
I have also tried using
SELECT * FROM table WHERE TIMESTAMPDIFF(MINUTE,timestamp,NOW()) > 10
Where I am not sure what is going on is first is my syntax correct and second how to do associate this query with a label so I can echo it. My full PhP code looks like this
SELECT * FROM table WHERE TIMESTAMPDIFF(MINUTE,timestamp,NOW()) > 10
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)) {
echo $row[0];
}
I was assuming I could use something like this to echo the results, but I get nothing to the screen. Can anyone point me in the right direction?
echo $row[0];
AS thisisit in this case have to be used to set an alias to your column.
So, you should use the following:
SELECT timestamp AS 'thisisit'
FROM table
WHERE TIMESTAMPDIFF(MINUTE, timestamp, NOW()) > 10;
I am using custom SQL to join two tables, apply some business logic to dates, then use the results to hydrate a propel object (collection). Here's my code:
$testtypes = TesttypeQuery::create()->find();
foreach ($testtypes as $testtype) {
/* work out what most recent schedule */
$con = \Propel::getConnection(SchedulePeer::DATABASE_NAME);
$sql = "SELECT `schedule`.*, (`schedule`.`last` + INTERVAL `duration`.`weeks` WEEK + INTERVAL `duration`.`months` MONTH + INTERVAL `duration`.`years` YEAR) AS `dueDate` FROM `schedule` LEFT JOIN `duration` ON `schedule`.`duration_id` = `duration`.`id` HAVING `schedule`.`testtype_id` = {$testtype->getId()} AND `dueDate` < NOW() ORDER BY `dueDate` ASC LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute();
$formatter = new \PropelObjectFormatter();
$formatter->setClass(SchedulePeer::OM_CLASS);
$schedules = $formatter->format($stmt);
// more stuff here ...
}
This question comes in several parts, because there might be a completely better way of doing this - so please feel free to make suggestions other than just answering my specific questions:
I am using HAVING instead of WHERE so that I can use the aliased column dueDate, which I want to use as part of the check and order, as well as returning it as part of the result-set to use later. Is there a way to grab this value but still hydrate the propel object? When I use fetch() or other PDO methods on $stmt I can no longer use this with the call to format().
Alternatively is there a better way to do this with pure Propel?
You should add some steps. This is the logical process:
SQL call that does not include the extra columns
Hydrate the object(s)
SQL call the returns values for the extra columns
Update the hydrated object(s) with the extra column values
Hope this helps. Cheers.