Is it possible to use subquery when updating an ActiveRecord?
I have a products table with following columns
id number_of_orders
1 3
2 3
3 2
and an items table
id product_id
1 1
2 1
3 1
4 2
5 2
6 2
7 3
8 3
What I want is
UPDATE products
SET number_of_orders = (
SELECT COUNT(id) FROM items WHERE product_id = 1
)
WHERE id = 1
I have tried
$subquery = ItemsModel::find()
->select('COUNT(id)')
->where(['product_id' => 1]);
ProductsModel::updateAll(
[
'number_of_orders' => $subquery
],
[
'id' => 1
]
);
and
$product = ProductsModel::findOne(1);
$product->number_of_orders = $subquery;
$product->save();
but none of this going to work.
Does anyone have any idea about solving this problem?
Conclusion:
Each of the two ways works very well after I updated to yii 2.0.14.
Try update Yii to the last version. Since 2.0.14 all instances of yii\db\ExpressionInterface (including Query and ActiveQuery) should be handled properly and generate SQL in similar way as yii\db\Expression. So all this should work in Yii 2.0.14 or later:
$subquery = ItemsModel::find()
->select('COUNT(id)')
->where(['product_id' => 1])
ProductsModel::updateAll(
['number_of_orders' => $subquery],
['id' => 1]
);
$product = ProductsModel::findOne(1);
$product->number_of_orders = $subquery;
$product->save();
ProductsModel::updateAll(
['number_of_orders' => new Expression('SELECT COUNT(id) FROM items WHERE product_id = 1')],
['id' => 1]
);
Last example should work also in earlier versions of Yii.
You can use count() to get number of records.
$itemCount = ItemsModel::find()
->where(['product_id' => 1]);
->count();
$product = ProductsModel::findOne(1);
$product->number_of_orders = $itemCount;
$product->save();
i would prefer:
$model = ProductsModel::findOne(1);
$model->updateAttributes(['number_of_orders' => ItemsModel::find()->where(['product_id' => 1])->count()]);
or you can do
$query = Yii::$app->db
->createCommand(sprintf('UPDATE %s SET number_of_orders=(SELECT COUNT(*) FROM %s WHERE product_id=:id) WHERE id=:id', ProductsModel::tableName(), ItemsModel::tableName()), [':id' => $id, ])
->execute();
ps: if both tables are the same, you have to do:
$query = Yii::$app->db
->createCommand(sprintf('UPDATE %s SET number_of_orders=(SELECT * FROM (SELECT COUNT(*) FROM %s WHERE product_id=:id) xxx) WHERE id=:id', ProductsModel::tableName(), ItemsModel::tableName()), [':id' => $id, ])
->execute();
Related
So let's just begin with the question.
I have a database with following structure:
id
first_user_id
second_user_id
1
1
2
1
2
4
1
2
1
And let's say i have a variable with id=1
$id = 1
I find the needed records with this.
Model::where('status',1)
->where('first_user_id', $id)
->orWhere('second_user_id',$id)->get();
I want to get all of the ids that is not equals to the $id in some of the columns.
For exampe:
if first_user_id is equals to $id
return second_user_id column
if second_user_id is equals to $id
return first_user_id column
I want to done that with Laravel Collections if it is possible?
The result must be array with the ids from condition above.
Example output:
Array
(
[0] => 2 // second_user_id from first record
[1] => 2 // first_user_id from the last record.
)
For more clearly here is some pseudo php code for what i exactly want
<?php
$students = [
[
"first_user_id" => 1,
"second_user_id" => 2
],
[
"first_user_id" => 2,
"second_user_id" => 3
],
[
"first_user_id" => 1,
"second_user_id" => 3
],
[
"first_user_id" => 4,
"second_user_id" => 6
],
];
$var = 2; // Authenticated user
$arr = [];
foreach($students as $student) {
if($student['first_user_id'] == $var || $student['second_user_id'] == $var) {
if($student['first_user_id'] == $var) {
$arr[] = $student['second_user_id'];
} else $arr[] = $student['first_user_id'];
}
}
print_r($arr);
Output:
Array
(
[0] => 1
[1] => 3
)
Thank you.
I guess you can use union in that case
$first = DB::table('users')
->where('second_user_id',$id)
->select('first_user_id as user_id');
$users = DB::table('users')
->where('first_user_id',$id)
->select('second_user_id as user_id')
->union($first)
->get(['user_id']);
In SQL it would be like
select first_user_id as user_id from users where second_user_id = :id
union
select second_user_id as user_id from users where first_user_id = :id
I'm trying to insert records to either two tables or one table depending on if a record exists or not.
First table Authors
ID | Name
1 | Joe
2 | Sam
Second table Books
ID | author_ID | Book
1 | 2 | Book1
2 | 2 | BookYYY
3 | 1 | BookABC
What I want to accomplish is to check if author exists first, if not insert author and his book and if it DOES exists insert just the book with the right author ID
Here is what I've attempted so far that doesn't seem to work.
$result = DB::table('authors')
->where('name', $data['author_name'])
->where('username', $data['author_username'])->pluck('id');
if(is_null($result)){
//Not in table add new author
$id = DB::table('authors')->insertGetId(
['name' => $data['author_name'], 'username' => $data['author_username']]
);
//Add book
DB::table('books')->insert(
['author_id' => '.$id.', 'name' => "Book777"]
);
}
else{
//Is in table insert just book
DB::table('books')->insert(
['author_id' => '.$result.', 'name' => "Book777"]
);
}
So I'm trying to add author with Book name "Book777" but if author does exists in DB get the author ID and insert just the book.
Thank you all for helping me with this! Appreciate any help.
Consider using ORM. With Eloquent you can change all your code to just this:
$author = Author::firstOrCreate(['name' => $data['author_name'], 'username' => $data['author_username']]);
$author->books()->create(['name' => 'Book777']);
With Query Builder you can do this:
$attributes = [
'name' => $data['author_name'],
'username' => $data['author_username']
];
$author = DB::table('authors')->where($attributes)->first();
$authorId = is_null($author) ? DB::table('authors')->insertGetId($attributes) : $author->id;
DB::table('books')->insert(['author_id' => $authorId, 'name' => "Book777"]);
I'm not sure if it's work or not but hope this helps
$result = DB::table('authors')
->where('name', $data['author_name'])
->where('username', $data['author_username'])->pluck('id');
if(!empty($result)){
//Is in table insert just book
DB::table('books')->insert(
['author_id' => $result, 'name' => "Book777"]
);
}
else{
//Not in table add new author
$id = DB::table('authors')->insertGetId(
['name' => $data['author_name'], 'username' => $data['author_username']]
);
//Add book
DB::table('books')->insert(
['author_id' => $id, 'name' => "Book777"]
);
}
This question already has answers here:
Laravel 5: syncing an extra field via pivot
(2 answers)
Closed 7 years ago.
Here is my code:
public function updateGroupIntoDatabase(){
$group_id = 6;
$group = Group::find($group_id);
$group -> name = Input::get('groups');
$projectsIds = Input::get('projects');
$userIds = array_merge(Input::get('clients'),Input::get('workers'));
array_push($userIds, Auth::id());
$adminId = Auth::id();
if($group -> save()){
foreach($userIds as $userId){
$name = User::find($userId);
$group -> projects() -> sync($projectsIds,array('admin_id' => $adminId, 'user_id' => $userId,'user_name' => $name -> name));
}
when I execute this I get like this:
id project_id group_id admin_id user_id user_name
1 4 6 0 0
But it should for each user_id create new record... When I use attach method It works find but when I use sync it create just one record with additional pivot fields filds 0. Any solution for this?
When using sync with pivot data:
$group->projects()->sync( array(
1 => array( 'admin_id' => $adminId, 'user_id' => $userId ),
2 => array( 'admin_id' => $adminId, 'user_id' => $userId ),
...
));
I have project_group pivot table with this fields: id, group_id, project_id, admin_id, user_id
This I use to attach group and projects together:
$group -> projects() -> attach($projects,array('admin_id' => Auth::user()->id));
Is it possible to for every record in that pivot table add diffirent user_id.
For example:
First record:
id = 1, group_id = 1 project_id = 2 admin_id = 1 user_id = 1
Second record:
id = 2, group_id = 1 project_id = 3 admin_id = 1 user_id = 1
3th record:
id = 3, group_id = 1 project_id = 2 admin_id = 1 user_id = 2
4th record:
id = 3, group_id = 1 project_id = 3 admin_id = 1 user_id = 2
Basicly if I select 2 projects from projects html list and 2 users from html users list I need to get result like in example above...
Sure, like this:
$projects = [
2 => ['admin_id' => 1, 'user_id' => 1],
3 => ['admin_id' => 1, 'user_id' => 2],
// and so on
];
$group->projects()->attach($projects);
And if I understood your problem right, you can build such an array like this:
$projectsIds = [2,3];
$userIds = [1,2];
$projects = [];
$adminId = Auth::id();
foreach($userIds as $userId){
$projects += array_fill_keys($projectIds, [
'admin_id' => $adminId,
'user_id' => $userId
]);
}
$group->projects()->attach($projects);
Here is one solution, if someone has better way please put here...
$projectsIds = [11,33];
$userIds = [1,2,4];
$adminId = Auth::id();
if($group -> save()){
foreach($userIds as $userId){
$group -> projects() -> attach($projectsIds,array('admin_id' => $adminId, 'user_id' => $userId));
}
How to achieve this query in phalcon using query builder (best method):
$results = "select * from table where name like 'A%' limit 10"; // <-- 10 records
$total = "select count(1) from table where name like 'A%'"; // <-- 100 records
return [
'data' => $result,
'total' => $total
];
im extjs user and i need to get total over limit to display paging information (eq: displaying 1 to 10 from 100 records)
thx.
You can achieve this with Pagination, see here: Pagination Docs
Only thing is to use QueryBuilder adapter. But this can be done with:
$builder = $this->modelsManager->createBuilder()
->from('Table')
->andWhere('name like :name:', array('name' => 'A%' ) );
$paginator = new Phalcon\Paginator\Adapter\QueryBuilder(array(
"builder" => $builder,
"limit"=> 10,
"page" => 1
));
return [
'data' => $paginator->items,
'total' => $paginator->total_items
];