How can I write a following sql in rails? - sql

update table_name set filename = CONCAT(filename, "test") where id = 111
How can I write the above SQL with ActiveRecord syntax in Rails ?

If you have model associated with given table, you can do:
m = Model.find(111)
m.update_column(:filename, m.filename + 'test')
If you want to to update multiple records:
Model.update_all('filename = CONCAT(filename, "test")')
or limit scope of elements with conditions:
Model.where(...).update_all(...)

Related

Active Record query for update between two ids in YII2 without using row query

I am noob in the YII2.
I am searching for an update query using Active Record in Yii2.
I need to update some record which are between two ids.
The Query:
UPDATE
table_name
SET status_name = 1
WHERE
id BETWEEN 1 AND 10;
What I have tried in Active Record:
$command = Yii::$app->db->createCommand('UPDATE table_name SET status_name = 1 WHERE id BETWEEN 1 AND 10 ');
$command->execute();
But I need Activerecord query without using row SQL queries.
You can use static updateAll method from Active Record:
TableName::updateAll(['status_name' => 1], 'id BETWEEN 1 AND 10');
Or query builder:
Yii::$app->db
->createCommand()
->update(
'table_name',
['status_name' => 1],
'id BETWEEN 1 AND 10'
)
->execute();
Like an another solution to question mentioned you can use Update counters:
Updating Counters
It is a common task to increment or decrement a column in a database table. We call these columns "counter columns". You can use updateCounters() to update one or multiple counter columns. For example,
$posts = TableName::find()->where(['between', 'id', "1", "10" ])->all();
$posts->updateCounters(['status_name' => 1]);
Note: If you use yii\db\ActiveRecord::save() to update a counter
column, you may end up with inaccurate result, because it is likely
the same counter is being saved by multiple requests which read and
write the same counter value.
Update:
Like mentioned in comments for Events like EVENT_AFTER_UPDATE to be occur You should do something like this:
$model = TableName::findOne()->where(['between', 'id', "1", "10" ])->all();
$model->status_name = new \yii\db\Expression('status_name + 1');
$model->save();
This issue was discussed here: Event EVENT_AFTER_UPDATE does not occur when updateCounters

Is this block of code efficient?

I am trying to assign a variable tagcolor only if it already exists in the database. This code queries the DB twice if the color is present, once to determine if it does indeed exist and another to actually assign it.
If it doesn't exist I just want to assign tagcolor to the user provided color.
if Tagmap.where("name = ? AND user_id = ?", tag, current_user.id).first.present?
tagcolor = Tagmap.where("name = ? AND user_id = ?", tag, current_user.id).first.color
else
tagcolor = params[:color].downcase
end
Can I reduce this block so I just query the DB once?
Provided you're on Rails 4, you can do:
tagcolor = Tagmap.find_by(name: tag, user: current_user).try(:color) || params[:color].downcase
Similar (but not that pretty) construction is possible in Rails 3:
tagcolor = Tagmap.find_by_name_and_user(tag, current_user).try(:color) || params[:color].downcase

Rails Mysql2::Error: Operand should contain 1 column(s)

I wanted to take this method:
self.spend_on_scholarships_for_african_people = training_programs.scholarships.joins(:participants).where('participants.race' => AFRICAN_RACES).sum('participants.spend')
and now want break it into different genders. We capture gender within the participants table. so i tried using active records array conditions within the query to do so like this:
self.bursary_spend_on_potential_female_employees = training_programs.scholarships.joins(:participants).where('participants.race = ? AND participants.gender = ?', AFRICAN_RACES, 'Female').sum('participants.spend')
self.bursary_spend_on_potential_male_employees = training_programs.scholarships.joins(:participants).where('participants.race = ? AND participants.gender = ?', AFRICAN_RACES, 'Male').sum('participants.spend')
But i keep getting the following error:
ActiveRecord::StatementInvalid - Mysql2::Error: Operand should contain 1 column(s): SELECT SUM(participants.spend) AS sum_id FROM `training_programs` INNER JOIN `participants` ON `participants`.`training_program_id` = `training_programs`.`id` WHERE `training_programs`.`skills_development_id` IS NULL AND `training_programs`.`skills_development_type` = 'SkillsDevelopment' AND `training_programs`.`scholarship` = 1 AND (participants.race = 'African','Coloured','Indian' AND participants.gender = 'Female'):
I have cut up my query and i can't seem to find what i have done wrong?
participants.race = 'African','Coloured','Indian'
should be
participants.race IN ('African','Coloured','Indian')
To get that SQL result, change the way you build your query to something like:
participants.race IN (?)

How to pass parameter to exists clause?

I have the following method in my model:
def is_user_in_role (security_user_id, role)
SecurityUser.joins(:security_users_roles)
.where(security_users_roles:{role:role})
.exists?("security_users.id=#{security_user_id}")
end
The issue is that the "security_user_id" is not "translated" correctly in the SQL statements. It is always interpreted as "0".
This is a simple output of the generated SQL passing 'Instructor' and '9' as parameters values:
SecurityUser Exists (0.0ms) SELECT 1 AS one FROM security_users INNER JOIN security_users_manage_securities ON security_users_manage_securities.security_user_id = security_users.id INNER JOIN security_users_roles ON security_users_roles.id = security_users_manage_securities.security_users_role_id WHERE security_users_roles.role = 'Instructor' AND security_users.id = 0 FETCH FIRST ROW ONLY
You can see at the end:
security_users.id = 0
Could you tell me how should I transform the exists clause in order to use it with parameter?
I have found it. In order to pass parameters in the exists clause, you should use an array like this:
def is_user_in_role (security_user_id, role)
SecurityUser.joins(:security_users_roles)
.where(security_users_roles:{role:role})
.exists?(["security_users.id=#{security_user_id}"])
end

Rails botches the SQL on a complex save

I am doing something seemingly pretty easy, but Rails is messing up the SQL. I could just execute my own SQL, but the framework should be able to handle this.
Here is the save I am trying to perform:
w = WhipSenVote.find(:first, :conditions => ["whip_bill_id = ? AND whip_sen_id = ?", bill_id, k])
w.votes_no = w.votes_no - 1
w.save
My generated SQL looks like this:
SELECT *
FROM "whip_sen_votes"
WHERE (whip_bill_id = E'1' AND whip_sen_id = 7)
LIMIT 1
And then:
UPDATE "whip_sen_votes"
SET "votes_yes" = 14, "updated_at" = '2009-11-13 19:55:54.807000'
WHERE "id" = 15
The first select statement is correct, but as you can see, the Update SQL statement is pretty wrong, though the votes_yes value is correct.
Any ideas? Thanks!
It would help to see the WhipSenVote model.
you can also use decrement!