I am trying to execute a query in PHP, but this code wouldn't work for some reason, it doesn't detect the keywords at all(DECLARE, SELECT, WHERE). Is there anything I can do and after all can I even use DECLARE in PHP as a mySQLi statement.
$sql2 ="DECLARE #MaxID INT; SELECT #MaxID = MAX(productID) FROM products; UPDATE sunglasses SET sunglassesId = #MaxID WHERE sunglassesId = 0;";
After all I am trying to update a field in Table1 where its initial value is 0 with a value from a field in Table2.
Hope that made sense.
P.S tried this query in Microsoft SQL Management studio and it worked, in PHP it doesnt.
change your query to this and you don't need any other variable:
UPDATE sunglasses
SET sunglassesId = (SELECT MAX(productID) FROM products)
WHERE sunglassesId = 0;
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.
I have a Large_table with fields named 1 (ID) thru 10 and 10k plus rows.
The Update statement causes things to slow down to a point where some records fail to update at all.
If I run
UPDATE Large_table SET SOME_FIELD = '$testdata'
it takes <1 sec from the PHP ,so its the WHERE clause that is the issue.
Running
UPDATE Large_table SET SOME_FIELD = 'apple' WHERE ID ='1'
from the php where it is in the foreach loop and so runs 10k times >30 sec and time out.
I need to:
1 fetch all the rows ( could fetch single row if i do a pre select but that seams like doubling up and the fetch appears efficient and quick).
Fetching all the data as in a lot of rows we need all the data in others there is only some fields, but that changes daily.
$stmt = $conn->prepare("SELECT * FROM Large_table "); $stmt->execute(); // Works quick.
foreach ($stmt as $row){
echo $row['1'];// works at .8 sec sometimes less
$testdata = 'apple';
//PHP CONSTRUCT THE OUTPUT Field for each row differently depending upon id and other feilds - so for testing lets call it $testdata = 'apple' and assume it changes as the issue is not in this part
$stmt = $conn->prepare("UPDATE Large_table SET SOME_FIELD = '$testdata' WHERE ID = '$row['1']' "); $stmt->execute();
}
I tried the CASE THEN WHEN complied approach but the sql statement becomes horrendous so surly cannot be the best way of doing this.
So What is the quickest most efficient way to achieve this ?
Try preparing the update statement and binding the parameters outside the foreach and then within the foreach set the parameters and execute the statement.
$update = $conn->prepare("UPDATE Large_table SET SOME_FIELD = ? WHERE ID = ?");
$update->bind_param('si', $testdata, $id);
foreach ($stmt as $row)
{
$id = $row[1];
$testdata = 'apple'; // I'm guessing in the real code this changes per row?
$update->execute();
}
If this still takes too long then you can always use set_time_limit(0).
It appears that the dB table itself had a issue which showed no detectable errors other than this write issue.
so
Export table as text (SQL dump)
Drop table
Restore table (with the SQL dump backup)
Now the THEN WHEN method is the quickest until the statement length reaches its max.
The next fastest is the bind_param outside of the foreach loop, version as suggest by Michael ( thanks) which is what is currently working.
I'm trying to update a value of a column using the codeigniter query function like this:
$this->db->query("UPDATE table SET val = val + 1 WHERE name = 'xxxxx');
Is there any way to get the result of this update in the same query function? I have to do a select query in order to do it and it's dangerous because of the amount of users this application is managing.
If there is another query in between the update and the select, the result would not be correct.
Thanks!
Use transaction and for update. This is an example from zend, which is a similar kind of db accessing thing:
$db->beginTransaction();
$val = $db->select()->forUpdate()->from('table', 'val')->orderBy('val DESC')->limit(1)->query()->fetchColumn();
$db->update('table', 'val = '.($val+1), 'name = "xxx"');
$db->commit()
The for-update with the transaction prevents another query interfering.
Learn more about for update here: http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
and about codeigniter transactions here: http://ellislab.com/codeigniter/user-guide/database/transactions.html (thanks to #Nanne for that)
Problem
I have a table tbl_student_courses which join 2 tables student and courses now when data is inserted it is the combination of 2 ids course_id and student_id. I just want there would be no duplication of this combination in tbl_student_courses.
Code
foreach($_POST['sel_course'] as $val) {
$query_std_course = "
INSERT INTO
`tbl_student_courses`
SET
`course_id` = '".$val."',
`std_id` = '".$_POST['std']."',
WHERE NOT EXISTS (
SELECT * FROM `tbl_student_courses` WHERE course_id=$val AND std_id=$std
)";
}
Help
This query giving SQL syntax error.
Can any body help me?
Thanks in advance.
Probably you are missing quotes one inner query values.
You SQL query should look like this
$sql = "
INSERT INTO
`tbl_student_courses`
SET
`course_id` = '".$val."',
`std_id` = '".$_POST['std']."',
WHERE NOT EXISTS (
SELECT * FROM `tbl_student_courses` WHERE course_id='".$val."' AND std_id='".$std."'
)";
NOTE: Inserting in database not prepared statements like std_id = '".$_POST['std']."' is not of a good manner. Consider using PDO or filter data yourself, bec. this can be easily used for SQL Iinjection therefore it is potential security breach.
UPDATE: Try to use ON DUPLICATE KEY UPDATE or INSERT IGNORE INTO table.
You can find more information regarding your implementation - http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
And read about proposed implementation - http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html
The SQL syntax you seek is the MERGE statement, or its equivalent on your platform
http://en.wikipedia.org/wiki/Merge_(SQL)