cakePHP: updating mysql table using WHERE clause with multiple conditions - mysql

I want to write this SQL statement in cakePHP syntax:
UPDATE students SET status = 'graduated' WHERE age = '23' AND major = 'math';
Now, the way I am trying to do this in cake is
$student->updateAll( array('Student.status' => "'".$rowdata."'"),
array('Student.age' => $current_highest_age,'Student.major' =>
"'".$major."'"));
My variables: $rowdata = 'graduated'; $current_highest_age = 23; and $major = 'math'.
The table is not being updated. Is there a problem with my syntax? I will appreciate your help.
UPDATE ON THE QUESTION:
Actually, I found out where I was wrong in my syntax. The cake code should be 'Student.major' => $major instead of 'Student.major'=>"'".$major."'"

You are double escaping
updateAll expects the fields to be SQL expressions (or simply quoted strings) but the conditions should not be. As such, the query you're going to be generating right now is:
UPDATE
students
SET
status = 'graduated'
WHERE
age = '23' AND
major = '\'math\''
To prevent the extra quotes, which will cause the syntactically-valid statement to match 0 rows, just let Cake take care of your conditions for you as with other methods:
$student->updateAll(
array('Student.status' => "'".$rowdata."'"),
array(
'Student.age' => $current_highest_age,
'Student.major' => $major
)
);

Easy way to update a field of a Model
$this->Testing->updateAll(
array('Testing.door_open_close' => $door_open_close), // value that is updated
array('Testing.id' => $zoneId) // condition field of a Model
);

UPDATE students ...
^^^^^^^^--- student WITH an S
v.s.
array('Student.age')
^^^^^^^ - student WITHOUT an S

Related

Update a column value if two specific conditions are met in MySQL

I'm very much a newbie to programming.
I am trying to update my table column labelled 'bonus' with a new value of 505.99 if two conditions are met: if the givenname is Mary and their bonus is currently 155.99, or if their occupation is a Model and their bonus is also currently 155.99. 7 rows should be updated but only 1 is being updated.
The query looks like it should work to me so wondering what I am missing?
Looking for any pointers!
Thanks in advance
UPDATE customers
SET bonus = 505.99
WHERE occupation = 'Model' AND bonus = 155.99
OR givenname = 'Mary' AND bonus = 155.99;
Can you try to use parentheses like these?
UPDATE customers
SET bonus = 505.99
WHERE
(occupation = 'Model' AND bonus = 155.99)
OR
(givenname = 'Mary' AND bonus = 155.99);
You should use AND and OR conditions properly when you use those simultaneously.
Let us build your query :
As we know we are going to set value wherever following holds true.
Either occupation = 'Model' OR givenname = 'Mary'
This should be written with OR together
bonus = 155.99 : This we can add separately using AND in the select query.
So; the correct condition to use is (occupation = 'Model' OR givenname = 'Mary') and bonus = 155.99;
We can re-write the above query as :
UPDATE customers
SET bonus = 505.99
WHERE bonus = 155.99
AND (occupation = 'Model' OR givenname = 'Mary');
You can find more good examples here :

SQL: Binding an undef (NULL) to the placeholder will not select rows which have a NULL value

I'm using perl 5.20 and MySQL 5.7, but I think the question is about SQL in general:
perldoc DBI says:
Binding an undef (NULL) to the placeholder will not select rows which have a NULL age! At least for database engines that conform to the SQL standard. Refer to the SQL manual for your database engine or any SQL book for the reasons for this. To explicitly select NULLs you have to say "WHERE age IS NULL".
I don't even know what to google for... My question is: What are the reasons behind = ? not matching a binding to NULL/undef? (Beyond "that is how it is defined and documented".)
I've discovered that MySQL has an operator <=> that allows comparisons with NULL and so:
my $sth = $dbh->prepare('select count(*) from table where field <=> ?');
$sth->execute(345);
$sth->execute(undef);
both work as expected. Unfortunately, the doc says:
The <=> operator is equivalent to the standard SQL IS NOT DISTINCT FROM operator.
And MySQL doesn't support the IS NOT DISTINCT FROM operator :-(. So there seems to be no portable way to do this. Except for the very hackish:
my $sth = $dbh->prepare('
select count(*) from table
where field = ? OR ( ? IS NULL AND field IS NULL )
');
$sth->execute(345, 345);
$sth->execute(undef, undef);
or the even more hackish snippet from perldoc DBI
$sql_clause = defined $age? "age = ?" : "age IS NULL";
$sth = $dbh->prepare(qq{
SELECT fullname FROM people WHERE $sql_clause
});
$sth->execute(defined $age ? $age : ());
Is there a portable way to do WHERE FIELD = ? and have it do what I mean also with NULLs/undefs? What did I miss?
EDIT: I also came up with this workaround, which especially works great if field is a numeric type such as an INT, so we're sure the string "NULL" is not a possible non-NULL value.
my $sth = $dbh->prepare('
select count(*) from table
where COALESCE(field, "NULL") = COALESCE(?,"NULL")
');
$sth->execute(345);
$sth->execute(undef);
But performance goes out the window, as I don't think any indexes can be used....
I understand that this is not exactly what you asked for but if you use DBIx::Class, the ORM will do that lifting for you.
my $res = $schema->resultset('table')->search({ field => [345, undef] });
print $res->count;
It will be translated to this SELECT COUNT( * ) FROM table me WHERE ( ( field = ? OR field IS NULL ) ): '345'

MySQL IF returning nothing

I am trying to do some optimisation, currently post mysql work is done on the results to set a new paramter $class_subject... so i am trying get this already calculated in mysql...
SELECT
class_grade.results as results,
subjects.subject as subject,
subjects_pseudonyms.pseudonym as pseudonym,
IF( subjects_pseudonyms.pseudonym = null, subjects.subject, subjects_pseudonyms.pseudonym ) as class_subject
FROM
class_grade
INNER JOIN class ON class_grade.class_ID = class.class_ID
INNER JOIN subjects ON class.subject_ID = subjects.a_ID
LEFT JOIN subjects_pseudonyms ON class.subject_pseudonym_ID = subjects_pseudonyms.a_ID
WHERE
class_grade.teacher_ID = :teacher_id AND
class_grade.class_ID = :current_class_ID AND
class_grade.report_set_ID = :report_set_ID AND
class_grade.student_ID = :current_student_ID
In the above query the pseudonym might be null, if so I am attempting to set a new variable class_subject to be either subject or pseudonym...
The query runs fine, a results example is:
[results] => 71
[subject] => Law
[pseudonym] =>
[class_subject] =>
The problem is, the class_subject is not being populated..
Is there something wrong with my IF() cond?
Thanks,
John
You need to use IS NULL instead of = NULL or ISNULL()
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_isnull
ISNULL() can be used instead of = to test whether a value is NULL.
(Comparing a value to NULL using = always yields false.)

Sub Query at join not coming in right way

Hiii, Currently I am stuck with a problem. I am finding no way to remove quotes generated by the zend on query generation of a sub query which is placed in a join operation.
The $selectInnerQuery creates the sub query which is used in the join operation this is called as inneranswer table. This is used to join with answer table. $select is used for the final query. Please help me on this...
$selectInnerQuery= $sql->select()->from(array('answer' => 'tblanswer'))->columns(array('aid' => new Expression('answer.aid'),'count' => new Expression('count(answer.qid)')));
$innerstatement = $sql->getSqlStringForSqlObject($selectInnerQuery);
$select = $sql->select()->from(array('answer' => 'tblanswer'))->columns($fieldsToSelect);
$select->join(array('inneranswer' => $innerstatement), 'inneranswer.aid = answer.aid', array(),'inner');
The query that I am getting from zend is
SELECT `answer`.* FROM `tblanswer` AS `answer`
inner join `SELECT answer.aid AS ``aid``, count(answer.qid) AS ``count`` FROM ``tblanswer`` AS ``answer`` WHERE answer.qid !=0 GROUP BY answer.qid, answer.baid` AS `inneranswer` ON `inneranswer`.`aid` = `answer`.`aid`
I have tried new Expression but it does not work in join operation.
When you are specifying your $innerstatement on joining, specify as like "{$innerstatement}", this may solve your quotes problem and also check your inner statement query returns sql query or it returns as object.
Came across the same issue today. Join table array should contain Select object instead of select query.
$selectObj = $sql->select()->from(array('answer' => 'tblanswer'))->columns(array('aid' => new Expression('answer.aid'),'count' => new Expression('count(answer.qid)')));
$select = $sql->select()->from(array('answer' => 'tblanswer'))->columns($fieldsToSelect);
$select->join(array('inneranswer' => $selectObj), 'inneranswer.aid = answer.aid', array(),'inner');

Rails 3. Checking for true values in SQL

I need to check if the column exam has a value of true. So I set this up but it doesn't work...
#exam_shipments = Shipment.where("exam <> NULL AND exam <> 0 AND customer_id = ?", current_admin_user.customer_id)
# This one gives me error "SQLite3::SQLException: no such column: true:"
#exam_shipments = Shipment.where("exam = true AND customer_id = ?", current_admin_user.customer_id)
#exam_shipments = Shipment.where("exam = 1 AND customer_id = ?", current_admin_user.customer_id)
You should really just stick to AR syntax:
#exam_shipments = Shipment.where(:exam => true, :customer_id => current_admin_user.customer_id)
Assuming :exam is a boolean field on your Shipment model. ActiveRecord takes care of converting your query to the proper syntax for the given database. So the less inline SQL you write, the more database-agnostic and portable your code will be.
Why do you need do execute SQL?
It's much easier just to do
#exam_shipments = Shipment.find_by_id(current_admin_user.customer_id).exam?