ActiveRecord query using multiple conditions - ruby-on-rails

I have a employee data base that captures all employees for all companies the companies are referenced by a company_id
I want to do something like this
sql = "SELECT race, `foreign`, id_number, company_id, COUNT(*) FROM `employees` WHERE company_id = 52 AND race = `African` AND `foreign` = 1 GROUP BY id_number;"
temp_arr = []
ActiveRecord::Base.connection.execute(sql).each {|int| temp_arr << int }
Like this
employee_ids = Employees.where(company_id: company_id and race: 'African' and foreign: 1).pluck(:id_number)
I keep getting the following error
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'African' in 'where clause':
And have been reading the Ruby on Rails Guides and cant seem to find what i am looking for. sorry i have never done such a query before its probably formatted wrong or something

You have to replace 'and' with ','
Try as follow;
employee_ids = Employees.where(company_id: company_id, race: 'African', foreign: 1).pluck(:id_number)

Related

Rails + Friendly Id query for ids and slugs in joined model

I need to be able to search items by both id and slug.
I am using the gem friendly-id with rails to handle slugs.
I have a request where I am looking for "Products" that are linked to certain "Skills" which are retrieved through a join.
It looks like this :
Product.
joins(
"JOIN learning_items_skills
ON products.learning_item_id = learning_items_skills.learning_item_id"
)
.where('learning_items_skills.skill_id IN (?)', skill_ids)
.where('learning_items_skills.visible = (?)', true)
I need to handle the case where skill_ids can be either an array of slugs or and array of ids.
At the moment, when I give a slug I get this error as the id field cannot handle a slug representation :
ActiveRecord::StatementInvalid - PG::InvalidTextRepresentation: ERROR: invalid input syntax for type bigint: "installation-4708f434-55d8-4e72-9a13-812668137edb"
LINE 3: ...= (TRUE)) AND (learning_items_skills.skill_id IN ('installat...
The following code will handle slug correctly but wont work for ids :
joins(
"JOIN learning_items_skills
ON products.learning_item_id = learning_items_skills.learning_item_id
JOIN skills
ON skills.id = learning_items_skills.skill_id
"
)
.where('learning_items_skills.visible = (?)', true)
.where('skills.slug IN (?)', skill_ids)
How can I rewritte my query to solve this issue ?

how codeigniter join two tables to have both Id columns

I want to join two tables that I have both Id columns in join table by codeigniter.
I want both id column from comment and users tables
I write below code
$this->db->select('users.name as user_full_name, users.id as userid', false);
$this->db->from('users');
$this->db->select()
->from('comment')
->where('project_id', $projectId)
->where('user_id', $user_id)
->join('users', 'comment.user_id_from =userid')
->order_by("comment.id", "asc");
return $this->db->get()->result_array();
but face error, I do not know why
error:
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '* FROM (users, comment) JOIN users ON comment.user_id_from =userid W' at line 1
SELECT users.name as user_full_name, users.id as userid, * FROM (users, comment) JOIN users ON comment.user_id_from =userid WHERE project_id = '3' AND user_id = '84' ORDER BY comment.id ASC
please show me how to solve it
try this:
$this->db->select('*,comment.id as comment_id,users.user_id as user_id,users.name as user_name');
$this->db->from('comment');
$this->db->where('user_id', $user_id);
$this->db->join('users', 'users.user_id = comment.id');
$this->db->order_by("comment.id", "asc");
return $this->db->get()->result_array();
it return all user and comment table data
may be this codeigniter query help you out

Fetch records from multiple tables by JOIN in rails 2

I have my records set up as follows
UserKycScanResults: id, user_kyc_scan_id, match_name <- belongs to UserKycScan
UserKycScan: id, user_id, created_at <- belongs to User
User: id, firstname, lastname
I'm trying to write a join so that I can find users' firstname who have a entry in the user_kyc_scans table and user_kyc_scan table entry date is yesterday along with their match_name from user_kyc_scan_results table if present.
I have tried the following
UserKycScanResult.joins("INNER JOIN user_kyc_scans ON user_kyc_scans.id = user_kyc_scan_results.user_kyc_scan_id
INNER JOIN users ON users.id = user_kyc_scans.user_id").where("users.name = '#{submitted_first_name}', user_kyc_scans.created_at = #{Date.yesterday} ")
But this approach doesn't work. Any help would be appreciated.
And joins and where clauses are not working on rails 2
Please give me any solution to sort this out
Thanks.
Your inner joins query are right but in rails 2 we have to pass joins and conditions these way:
UserKycScanResult.all(:joins => "INNER JOIN user_kyc_scans ON user_kyc_scans.id = user_kyc_scan_results.user_kyc_scan_id
INNER JOIN users ON users.id = user_kyc_scans.user_id",
:conditions => ["users.name = ? AND user_kyc_scans.created_at = ?", submitted_first_name, Date.yesterday])
Document for reference: ruby on rails guides
Happy Coding

Rails Postgres query to exclude any results that contain one of three records on join

This is a hard problem to describe but I have Rails query where I join another table and I want to exclude any results where the join table contain one of three conditions.
I have a Device model that relates to a CarUserRole model/record. In that CarUserRole record it will contain one of three :role - "owner", "monitor", "driver". I want to return any results where there is no related CarUserRole record where role: "owner". How would I do that?
This was my first attempt -
Device.joins(:car_user_roles).where('car_user_roles.role = ? OR car_user_roles.role = ? AND car_user_roles.role != ?', 'monitor', 'driver', 'owner')
Here is the sql -
"SELECT \"cars\".* FROM \"cars\" INNER JOIN \"car_user_roles\" ON \"car_user_roles\".\"car_id\" = \"cars\".\"id\" WHERE (car_user_roles.role = 'monitor' OR car_user_roles.role = 'driver' AND car_user_roles.role != 'owner')"
Update
I should mention that a device sometimes has multiple CarUserRole records. A device can have an "owner" and a "driver" CarUserRole. I should also note that they can only have one owner.
Anwser
I ended up going with #Reub's solution via our chat -
where(CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not)
Since the car_user_roles table can have multiple records with the same car_id, an inner join can result in the join table having multiple rows for each row in the cars table. So, for a car that has 3 records in the car_user_roles table (monitor, owner and driver), there will be 3 records in the join table (each record having a different role). Your query will filter out the row where the role is owner, but it will match the other two, resulting in that car being returned as a result of your query even though it has a record with role as 'owner'.
Lets first try to form an sql query for the result that you want. We can then convert this into a Rails query.
SELECT * FROM cars WHERE NOT EXISTS (SELECT id FROM car_user_roles WHERE role='owner' AND car_id = cars.id);
The above is sufficient if you want devices which do not have any car_user_role with role as 'owner'. But this can also give you devices which have no corresponding record in car_user_roles. If you want to ensure that the device has at least one record in car_user_roles, you can add the following to the above query.
AND EXISTS (SELECT id FROM car_user_roles WHERE role IN ('monitor', 'driver') AND car_id = cars.id);
Now, we need to convert this into a Rails query.
Device.where(
CarUserRole.where("car_user_roles.car_id = cars.id").where(role: 'owner').exists.not
).where(
CarUserRole.where("car_user_roles.car_id = cars.id").where(role: ['monitor', 'driver']).exists
).all
You could also try the following if your Rails version supports exists?:
Device.joins(:car_user_roles).exists?(role: ['monitor', 'driver']).exists?(role: 'owner').not.select('cars.*').distinct
Select the distinct cars
SELECT DISTINCT (cars.*) FROM cars
Use a LEFT JOIN to pull in the car_user_roles
LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id
Select only the cars that DO NOT contain an 'owner' car_user_role
WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner')
Select only the cars that DO contain either a 'driver' or 'monitor' car_user_role
AND (car_user_roles.role IN ('driver','monitor'))
Put it all together:
SELECT DISTINCT (cars.*) FROM cars LEFT JOIN car_user_roles ON cars.id = car_user_roles.car_id WHERE NOT EXISTS(SELECT NULL FROM car_user_roles WHERE cars.id = car_user_roles.car_id AND car_user_roles.role = 'owner') AND (car_user_roles.role IN ('driver','monitor'));
Edit:
Execute the query directly from Rails and return only the found object IDs
ActiveRecord::Base.connection.execute(sql).collect { |x| x['id'] }

How to select max(date) and group by client_id?

So, I got this working the way I want in pure sql:
select * from clients c
join insurance_providers p on c.id = p.client_id
where p.effective_on =
(select max(effective_on)
from insurance_providers group by client_id having p.client_id = client_id)
and user_id = 2; #user_id =2 where 2 represents current_user.id
Here what I tried in the console:
Client.joins(:insurance_providers)
.select('max(insurance_providers.effective_on)')
.group(:client_id)
.where('user_id = 2')
It promptly exploded in my face with:
NoMethodError: undefined method `group' for Mon, 08 Jul 2013:Date
It looks like I'm just getting the date itself returned from the select statement. I need something like "where effective_on = .select('max..."
any help would be greatly appreciated.
UPDATE: I'm getting closer with this:
InsuranceProvider.maximum(:effective_on, :group => 'client_id')
but I'm not sure how to join the clients table in to get all the info I need.
In the rails console, both of these:
Client.joins(:insurance_providers).maximum(:effective_on, :group => 'client_id')
Client.joins(:insurance_providers.maximum(:effective_on, :group => 'client_id'))
cause this error:
NoMethodError: undefined method `group' for Mon, 08 Jul 2013:Date
UPDATE:
this is closer, but I need a having clause on the end - just not sure how to tie the inner table and outer table together (like in the sql: p.client_id = client_id):
insuranceProvider = InsuranceProvider.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers group by client_id)")
InsuranceProvider Load (1.0ms) SELECT "insurance_providers".* FROM "insurance_providers" WHERE (effective_on = (SELECT MAX(effective_on) FROM insurance_providers group by client_id))
PG::CardinalityViolation: ERROR: more than one row returned by a subquery used as an expression
: SELECT "insurance_providers".* FROM "insurance_providers" WHERE (effective_on = (SELECT MAX(effective_on) FROM insurance_providers group by client_id))
ActiveRecord::StatementInvalid: PG::CardinalityViolation: ERROR: more than one row returned by a subquery used as an expression
: SELECT "insurance_providers".* FROM "insurance_providers" WHERE (effective_on = (SELECT MAX(effective_on) FROM insurance_providers group by client_id))
UPDATE: here's some progress.
This seems to be what I need, but I don't know how to join it to the clients table:
InsuranceProvider.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers p group by client_id having p.client_id = insurance_providers.client_id)")
This gives me the insurance_providers grouped by the client_id. I need to join to this resultset on the client_id.
This does NOT work:
InsuranceProvider.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers p group by client_id having p.client_id = insurance_providers.client_id)").client
resulting in a "NoMethodError":
undefined method `client' for #<ActiveRecord::Relation::ActiveRecord_Relation_InsuranceProvider:0x007fe987725790>
UPDATE:
This is getting me the clients I need!
Client.joins(:insurance_providers).where("insurance_providers.effective_on = (SELECT MAX(effective_on) FROM insurance_providers p group by client_id having p.client_id = insurance_providers.client_id)")
But I can't get to the insurance_providers table. UGH! This is getting stickier....
UPDATE:
client.insurance_providers.order('effective_on DESC').first.copay
sometimes taking a break is all you need.
So, in my controller, I have this:
#clients = Client.joins(:insurance_providers)
.where("insurance_providers.effective_on = (
SELECT MAX(effective_on)
FROM insurance_providers p
GROUP BY client_id
HAVING p.client_id = insurance_providers.client_id
)")
Then in my view, I have this:
client.insurance_providers.order('effective_on DESC').first.copay
I'm not sure why you were getting the undefined method 'group' error with the select in your first query, it shouldn't return anything at that point until you attempt to use one of the fields explicitly, or call .load or .first, etc.
Maximum is not the way to go either because that WILL immediately return the data, and its basically the same as saying in SQL "SELECT MAX(effective_on) FROM insurance_providers", which is obviously not what you want.
To answer your question directly, to summarize what you're looking to do, I believe you're trying to find the Insurance Provider with the hightest effective_on date, and then be able to view the client associated with that provider. Please correct me if I am mistaken.
I think this will work:
insuranceProvider =
InsuranceProvider.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers)")
.group(:client_id)
You shouldn't need anything else beyond that. Notice how I'm invoking the query on the InsuranceProvider model instead; Remember that with Rails, you can easily get the model object's associated records using your has_many and belongs_to relationship descriptors.
Therefore, in order to get the associated Client model information, it is important that your InsuranceProvider class has a line that looks like belongs_to :client. This is required in this case, otherwise Rails doesn't know that this model relates to anything else. If you have that in there, then in order to get the Client information, all you simply need to do is
client = insuranceProvider.client
This will result in a second query which lazy-loads the client information for that insurance provider, and you're good to go.
EDIT
Based on the discussion in the comments, my original solution is not quite what you're looking for (and syntactically invalid for non-MySQL databases).
I answered a similar question here once that is somewhat related to this, so maybe that information could be helpful.
Basically, what I think you'll need to do is grab your list of Clients, or grab your single client object, whatever you need to do, and invoke the association with a .where clause, like so:
client = Client.first # this is for illustration so that we have a client object to work with
insurance_provider =
client.insurance_providers
.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers WHERE client_id = ?", client.id)
Or, if you want to avoid having to inject the client.id manually, you can cause a dependent subquery, like so:
insurance_provider =
client.insurance_providers
.joins(:client)
.where("effective_on = (SELECT MAX(effective_on) FROM insurance_providers WHERE client_id = clients.id")

Resources