Yii2 Update where the condition is an Array - mysql

This is the update code
$clients = OpClient::find(['id'])->where(['status'=>'Active'])->all();
foreach($clients as $client)
{
$array[] = $client['unit_id'];
$unit = OpUnit::find()->where(['id'=>$array]);
file_put_contents('test.txt',print_r($client['unit_id'],true));
$connection = Yii::$app->db;
$connection->createCommand()->update('op_unit', ['selected' => 'Yes'], 'id='.$array.'')->execute();
}
How should I type in the update query where the id is an array? It keep showing error Array to string conversion. Any advice will be apprecieated. Thanks

should be this way ..
$connection->createCommand()->update('user',
['selected' => 'Yes'],['id' => $array])->execute();
try the real sql code using
$myRawSql= $connection->createCommand()->update('user',
['selected' => 'Yes'],['id' => $array])>getRawSql();
var_dump($myRawSql);

For searching you can use the IN condition. i.e
->andWhere(['in', 'id', [1, 2, 3]])
// Query will be: WHERE id IN (1, 2, 3)
http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
in: operand 1 should be a column or DB expression. Operand 2 can be
either an array or a Query object. It will generate an IN condition.
If Operand 2 is an array, it will represent the range of the values
that the column or DB expression should be; If Operand 2 is a Query
object, a sub-query will be generated and used as the range of the
column or DB expression. For example, ['in', 'id', [1, 2, 3]] will
generate id IN (1, 2, 3). The method will properly quote the column
name and escape values in the range. The in operator also supports
composite columns. In this case, operand 1 should be an array of the
columns, while operand 2 should be an array of arrays or a Query
object representing the range of the columns.
So basically you need to pass your array to IN for search.
For update you can use same Where syntax in updateAll command i.e
// UPDATE customer SET status = 1 WHERE id IN (1, 2, 3)
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#updating-multiple-rows
Customer::updateAll(['status' => Customer::STATUS_ACTIVE], ['in', 'id', [1, 2, 3]]);
Hope this helps. Thanks.

You can use updateAll query :
$update = OpUnit::updateAll(['selected' => 'Yes'],['id' => $array]);
It returns number of rows updated.
Refer : http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html#updateAll()-detail

Related

Sql moving values from one column to two different columns

My problem is as follows - in the database I have a Products table with a size column. However, I have now created two new columns x_size and y_size and I wanted to move the values from the size column to these 2 columns. For example, in the database I have a record, where the size column value is 100x200, now I want to transfer '100' to the new x_size column and '200' to the y_size column, and so for each of the records in this table.
I was trying with :
UPDATE `post` SET `x_size `=`size`
UPDATE `post` SET `y_size `=`size`
But this updates the value of the entire size column, not just part of it. I will be grateful for your help
If you have multiple records that you want to transfer from size column, you could do fetch all the records from your table, and then split your size values using PHP explode() function. Since you tagged Laravel, here's the simple Laravel solution:
$products = Products::get();
foreach ($products as $product){
$size = explode('x', $product->size);
$product->x_size = $size[0]; //First element from exploded array
$product->y_size = $size[1]; //Second element from exploded array
$product->save();
}
Tinker output:
>>> $size = '100x200';
=> "100x200"
>>> $exlpodedArray = explode('x', $size);
=> [
"100",
"200",
]
>>> $x_size = $exlpodedArray[0];
=> "100"
>>> $y_size = $exlpodedArray[1];
=> "200"
You can use substring_index():
UPDATE post
SET x_size = substring_index(size, 'x', 1),
y_size = substring_index(size, 'x', -1)

Where in with array of values MYSQL

Lets say of I have this query SELECT * FROM table WHERE id IN (1,2,3,4);
In my current use case my ids are in an array like so [1,2,3,4]
How could I do the same query using the array data structure?
i.e. SELECT * FROM table WHERE id IN (myarray);
Edit: this is in ruby :)
Try this:
SELECT * FROM table WHERE id IN (myarray.map {|i| "\"#{i}\""}.join(", "));
You could convert the array to a comma separated string using the myarray.join(',') method.
The final code would look like this:
query = "SELECT * FROM table WHERE id IN (#{myarray.join(',')})"
You might run into some problems if the array values are strings, but it works just fine for integers.
User.where(id: [1, 2, 3, 4, nil]).to_sql
# SELECT "users".* FROM "users"
# WHERE ("users"."id" IN (1, 2, 3, 4) OR "users"."id" IS NULL)
or, if you can't/don't want to use where, you can drop into Arel to get just the IN string:
User.arel_table[:id].in([1,2,3,4]).to_sql
# => "users"."id" IN (1, 2, 3, 4)
though with this, you don't automatically get that nifty nil handling. If you don't have an ActiveRecord Model, but just using ActiveRecord::Base to execute queries in your database (as mentioned in the comments) you can do:
table = Arel::Table.new(:table) # :table is the name of the table in db
table[:id].in([1,2,3,4]).to_sql
# => "table"."id" IN (1, 2, 3, 4)
table.where(table[:id].in([1,2,3,4])).project(Arel.sql('*')).to_sql
# => SELECT * FROM "table" WHERE "table"."id" IN (1, 2, 3, 4)
And, avoiding Arel/ActiveRecord as much as possible, you can just do
ActiveRecord::Base.send(:sanitize_sql, ['id in (?)', [1,2,3,4]])
# => "id in (1,2,3,4)"

Mysql JSON column any index ( [*] ) not working

I have a JSON column named prices_and_tags in which there are values in JSON array:
[{'price' => 100, 'tag' => 'Watch'}, {'price' => 200, 'tag' => 'Book'}]
If I want to search prices_tags where tag = 'Watch' in any array index, it's not working.
Query is like this:
select * from products where prices_and_tags->"$[*].tag" = 'Watch'
this gives 0 results.
But this query works for first or second array index, like this:
select * from products where prices_and_tags->"$[0].tag" = 'Watch'
I referred to this: https://dev.mysql.com/doc/refman/5.7/en/json-path-syntax.html for query syntax.
Thanks.
Have you tried this
select * from products where prices_and_tags->"$.tag[*]" = 'Watch'
Ref: https://dev.mysql.com/doc/refman/5.7/en/json.html

CActiveRecord Find By Attributes Where Field Is Null

In Yii 1.1.*, how to find all data (via CActiveRecord implementation) where an attributes is NULL, kinda like:
Foo::model()->findAllByAttributes(['bar' => 'baz', 'qux' => [null, '']]);
It DOES NOT work because it produces query: WHERE (bar = 'baz') AND (qux IN (, ''))
I want to find all Foo records where:
"bar" field equals with "baz"
AND qux field IS NULL or equals with empty string
I can do it with findAll, but how about if I want to use findAllByAttributes method? Thanks.
Something like:
$cityModel = Cities::model()->findAllByAttributes(array("citny_name"=>"d"), "state_id IS NULL OR state_id = ''");
The executed query:
SELECT * FROM `cities` `t` WHERE `t`.`citny_name`=:yp0 AND
(state_id IS NULL OR state_id = ''). Bound with :yp0='d'
You can pass the condition for quz as an additional parameter into findAllByAttributes:
Foo::model()->findAllByAttributes(['bar' => 'baz'], "quz IS NULL OR quz = ''")
You can't use IN with null values unless you replace CDbCommandBuilder with your own implementation. CActiveRecord::findAllByAttributes calls CDbCommandBuilder::createColumnCriteria which in turn calls CDbCommandBuilder::createInCondition if the column values are an array.
From the source code values are cast into the column type and quoted afterwards and passed through implode resulting in the null being treated as php's null not mysql's null:
foreach($values as &$value)
{
$value=$column->typecast($value);
if(is_string($value))
$value=$db->quoteValue($value);
}
...
return $prefix.$column->rawName.' IN ('.implode(', ',$values).')';

How to use the table columns instead of variables in QueryExpression::addCase()

In CakePHPs new ORM, you can use the QueryBuilder to build (in theory) any query.
I want to select the value of one of two columns, depending on another value. In a regular query, that can be done as follows:
SELECT IF(from_id = 1, to_id, from_id) AS other_id FROM messages;
I am trying to archive the same query using the QueryBuilder and QueryExpression::addCase()
$messagesQuery = $this->Messages->find('all');
$messagesQuery->select([
'other_id' => $messagesQuery->newExpr()->addCase(
$messagesQuery->newExpr()->add(['from_id' => $this->authUser->id]),
['to_id', 'from_id'],
['integer', 'integer']
)
]);
This does not work, as the passed values are not integers, but rather table columns containing integers.
Through trial and error (using the method add() again), I got the following:
$messagesQuery = $this->Messages->find('all');
$messagesQuery->select([
'other_id' => $messagesQuery->newExpr()->addCase(
$messagesQuery->newExpr()->add(['from_id' => $this->authUser->id]),
[
$messagesQuery->newExpr()->add(['to_id']),
$messagesQuery->newExpr()->add(['from_id'])
],
['integer', 'integer']
)
]);
This results in the following query:
SELECT (CASE WHEN from_id = 1 THEN to_id END) AS `other_id` FROM messages Messages
Now, the ELSE part is missing, although the CakePHP book states:
Any time there are fewer case conditions than values, addCase will automatically produce an if .. then .. else statement.
The examples in the CakePHP book are not very helpful in this case, as they only use static integers or strings as values, for example:
#SELECT SUM(CASE published = 'Y' THEN 1 ELSE 0) AS number_published, SUM(CASE published = 'N' THEN 1 ELSE 0) AS number_unpublished FROM articles GROUP BY published
$query = $articles->find();
$publishedCase = $query->newExpr()->addCase($query->newExpr()->add(['published' => 'Y']), 1, 'integer');
$notPublishedCase = $query->newExpr()->addCase($query->newExpr()->add(['published' => 'N']), 1, 'integer');
$query->select([
'number_published' => $query->func()->sum($publishedCase),
'number_unpublished' => $query->func()->sum($unpublishedCase)
])
->group('published');
Is there a way to get the method addCase to use the two table columns as values instead of just static values?
As it turns out, I was just one logical step short of the solution in my previous edit.
As the CakePHP book correctly states:
Any time there are fewer case conditions than values, addCase will automatically produce an if .. then .. else statement.
For that to work though, both the conditions and values have to be an array, even if there is only one condition. (This the CakePHP book does not state.)
This code:
$messagesQuery = $this->Messages->find('all');
$messagesQuery->select([
'other_id' => $messagesQuery->newExpr()->addCase(
[
$messagesQuery->newExpr()->add(['from_id' => $this->authUser->id])
],
[
$messagesQuery->newExpr()->add(['to_id']),
$messagesQuery->newExpr()->add(['from_id'])
],
['integer', 'integer']
)
]);
results in this query:
SELECT (CASE WHEN from_id = 1 THEN to_id ELSE from_id END) AS `other_id` FROM messages Messages
Eureka