Rails 2.x query using IN with other conditions doesn't work as expected - mysql

I'm trying to write a Rails 2.1 query(I know that I should upgrade, but that's not my decision at the moment) which using the 'IN' condition. It doesn't seem to work as expected.
It only takes into consideration the roles_id = 21 based on the below query and it doesn't consider both the roles_id(i.e., 21 and 31) to display the correct count.
Admin.find(:all, :conditions => ["test_column1 = ? and roles_id IN (?) and test_column2 = ?",234, '21,31', 1]).count
Could one please tell me how can I get this right?
Thank you.

You need to pass an array I think
Admin.find(:all, :conditions => ["test_column1 = ? and roles_id IN (?) and test_column2 = ?",234, [21,31], 1]).count

Related

How to compare two fields/columns in a condition?

I am having a hard time trying to figure out how to get a sub-query working.
Imagine I have:
$schools
->select($this->Schools)
->select([
'pupilcount' => $this->Pupils
->find()
->select([
$this->Pupils->find()->func()->count('*')
])
->where([
'Pupils.school_id' => 'Schools.id',
]),
The problem I am experiencing (I think) is that Schools.id is always 0 and so the count is returned as 0. I can pull out the Pupils join and it shows Pupils there.
I tried changing my code to add a:
->select(['SCID' => 'Schools.id'])
and reference that in the sub-query but doesn't work, it will always return 0 for the pupilcount.
What am I doing wrong here?
Whenever encountering query problems, check what queries are actually being generated (for example using DebugKit). Unless being an expression object, the right hand side of a condition will always be bound as a parameter, ie you're comparing against a string literal:
Pupils.school_id = 'Schools.id'
Generally for proper auto quoting compatibility, column names should be identifier expressions. While the left hand side will automatically be handled properly, the right hand side would require to be handled manually.
In your specific case you could easily utilize QueryExpression::equalFields(), which is ment for exactly what you're trying to do, comparing fields/columns:
->where(function (\Cake\Database\Expression\QueryExpression $exp, \Cake\ORM\Query $query) {
return $exp->equalFields('Pupils.school_id', 'Schools.id');
})
It's also possible to create identifier expressions manually by simply instantiating them:
->where([
'Pupils.school_id' => new \Cake\Database\Expression\IdentifierExpression('Schools.id')
])
or as of CakePHP 3.6 via the Query::identifier() method:
->where([
'Pupils.school_id' => $query->identifier('Schools.id')
])
And finally you could also always pass a single string value, which is basically inserted into the query as raw SQL, however in that case the identifiers will not be subject to automatic identifier quoting:
->where([
'Pupils.school_id = Schools.id'
])
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
API > \Cake\Database\Expression\QueryExpression::equalFields()
API > \Cake\Database\Expression\IdentifierExpression

Specified method is not supported MySql Entity Framwork 6

I am trying to run the following Linq query from MySQL client
query = query.Where(c => c.CustomerRoles
.Select(cr => cr.Id)
.Intersect(customerRoleIds)
.Any()
);
This code looks okay, but gives the error:
System.NotSupportedException: Specified method is not supported.at MySql.Data.Entity.SqlGenerator.Visit(DbIntersectExpression expression)
This looks to me like an issue with .Intersect. Can anybody tell me the cause of this error and how to fix it?
i think #GertArnold's post is a correct and best of the answers, but i'm wonder why have you gotten NotSupportedException yet ? so the problem should not be from intersect probably.
where is customerRoleIds come from ? is it IQueryable<T> ?
break the query, and complete it step by step.
if you don't get exception at this lines:
var a = query.Select(c => new {
c,
CustomerRoleIDList = c.CustomerRoles.Select(cr => cr.Id).AsEnumerable()
})
.ToList();
var b = customerRoleIds.ToList();
you must get the result by this:
var b = query.Where(c => c.CustomerRoles.any(u => customerRoleIds.Contains(u.Id)))
.ToList();
if you get exception by above query, you can try this final solution to fetch data first, but note by this, all data will be fetched in memory first:
var a = query.Select(c => new {
c,
CustomerRoleIDList = c.CustomerRoles.Select(cr => cr.Id).AsEnumerable()
})
.ToList();
var b = a.Where(c => c.CustomerRoleIDList.any(u => customerRoleIds.Contains(u)))
.Select(u => u.c)
.ToList();
Using Intersect or Except is probably always troublesome with LINQ to a SQL backend. With Sql Server they may produce horrible SQL queries.
Usually there is support for Contains because that easily translates to a SQL IN statement. Your query can be rewritten as
query = query.Where(c => c.CustomerRoles
.Any(cr => customerRoleIds.Contains(cr.Id)));
I don't think that customerRoleIds will contain many items (typically there won't be hundreds of roles), otherwise you should take care not to hit the maximum number of items allowed in an IN statement.
query.Where(c => c.CustomerRoles
.Any(v=>customerRoleIds.Any(e=>e == v.Id))
.Select(cr => cr.Id))
.ToList();
Try adding toList() before intersect, that should enumerate results locally instead running on MySql, you will get performance hit thought.
query = query.Where(c => c.CustomerRoles.Select(cr => cr.Id)).ToList().Intersect(customerRoleIds);

Codeigniter mysql where not equal to query

Mysql codeigniter query is not working properly.
Suppose if mysql table looks like this:
user_id|user_name
1|john
2|alex
3|sam
Here user_name is unique
The following query should return false if user_name=john and user_id=1 and true if say user_name=john and user_id=2.
$this->db->get_where('user', array('user_name' => $name,'user_id !=' => $userid));
But it returns true in the case user_name=john and user_id=1.
Can anyone suggest me an alternative way of querying not equal to.
print($this->db->last_query()) gives:
SELECT * FROM (user) WHERE user_name = 'john' AND user_id != '1'
Why dont you use simple $this->db->query('your query');
Simply try this, Add the desired condition in the where function.
$this -> db -> where('invitee_phone !=', $user_phone);
You can go follwoing way too. It work for me
$total = 5;
$CI = get_instance();
$CI->load->database();
$CI->db->order_by('id','asc');
$topusers = $CI->db->get_where('users',array('user_type != 1 && `status` =' => 1),$total,0);
echo $CI ->db ->last_query();
die;
and if still not work for you can go with #rohit suggest: $this->db->query('your query');
Type 1:
Using ->where("column_name !=",$columnname) is fine for one column.
But if you want to check multi columns, you have to form an array inside where clause.
Like this
$whereArray = array(
"employee_name" => $name,
"employee_id !=" => $id,
);
$this->db->select('*')->from('employee')->where($whereArray);
Type 2:
We can just write exactly what we want inside where.
Like
$thi->db->where(("employee_id =1 AND employee name != 'Gopi') OR designation_name='leader#gopis clan'");
Type 2 is good for working with combining queries, i mean paranthesis "()"
you can follow this code:
$query = $this->db->select('*')->from('employee')->where('user_name', $name)->where('user_id !=', $userid)->get();
$last_query = $this->db->last_query();
$result = $query->result_array();
if you pass $name = 'john' and $userid = '1' then it return empty array.
The problem with using $this->db->query('your query'); is that it is not portable. One of the most important reasons to embrace the query builder methods is so that no matter what database driver you use, CodeIgniter ensures that the syntax is appropriate.
If a bit of discussion was possible, I'd probably like to hear why you need composite primary identifiers in your table and I'd like to see what your table schema looks like. However, I think the time for discussion has long passed.
Effectively, you want to return a boolean result stating the availability of the combination of the username AND the id -- if one is matched, but not both, then true (available).
To achieve this, you will want to search the table for an exact matching row with both qualifying conditions, count the rows, convert that integer to a boolean, then return the opposite value (the syntax is simpler than the explanation).
Consider this clean, direct, and portable one-liner.
return !$this->db->where(['user_name' => $name,'user_id' => $userid])->count_all_results('user');
this will return false if the count is > 0 and true if the count is 0.

Make a Mysql query that finds data just before another (in RoR)

I'm making this query to MySql
Image.find( :all,
:conditions => ["created_at > ? && approved = 1", #image.created_at],
:order => "created_at DESC", :limit => 5)
However, I want the images create just before the given image was created at. Right now, it's returning a list of images from the top of the list, that were create much, much before that image. How can I do this?
Your current query will find any images newer than #image because your using >. You'll need to decide what kind of range you're wanting to look in.. What time frame do you consider "just before"? Minutes? Seconds?
To find all images created within 5 mins of #image, try:
Image.find(:all, :conditions => ["(created_at > ? and created_at < ?) and approved = 1", #image.created_at.advance(:minutes => -5), #image.created_at])
My solution feels more like a hack, but I'm not sure of a better one. I set :order => "created_at ASC"... and then reversed the resulting array, and got the response I wanted. Hrm.

How can I get FOUND_ROW()s from an active record object in rails?

When querying the database with:
#robots = Robot.all(:condition => [:a => 'b'], :limit => 50, :offset => 0)
What is the best way to get the total number of rows without the :limit?
In raw MySQL you could do something like this:
SELECT SQL_CALC_FOUND_ROWS * FROM robots WHERE a=b LIMIT 0, 50
SELECT FOUND_ROWS();
Is there an active record way of doing this?
This works for me:
ps = Post.all(:limit => 10, :select => "SQL_CALC_FOUND_ROWS *")
Post.connection.execute("select found_rows()").fetch_hash
=> {"found_rows()"=>"2447"}
This will probably not work for joins or anything complex, but it works for the simple case.
Robot.count actually is the solution you want.
Reading one of the comments above, it looks like you may have a misunderstanding of how .count works. It returns a count of all the rows in the table only if there's no parameters.
but if you pass in the same conditions that you pass to all/find eg:
Robot.count(:conditions => {:a => 'b'})
.count() will return the number of rows that match the given conditions.
Just to be obvious - you can even save the condition-hash as a variable to pass into both - to reduce duplication, so:
conds = {:a => 'b'}
#robots = Robot.all(:conditions => conds, :limit => 50)
#num_robots = Robot.count(:conditions => conds)
That being said - you can't do an after-the-fact count on the result-set (like in your example). ie you can't just run your query then ask it how many rows would have been found. You do actually have to call .count on purpose.
search = Robot.all(:condition => ["a=b"], :offset => 0)
#robots = search[0..49]
#count = search.count
That should get what you want, gets all the Robots for counting and then sets #robots to the first 50. Might be a bit expensive on the resource front if the Robots table is huge.
You can of course do:
#count=Robot.all(:condition => ["a=b"], :offset => 0).count
#robots=Robot.all(:condition => ["a=b"], :limit => 50, :offset => 0)
but that will hit the database twice on each request (although rails does have query caching).
Both solutions only use active record so are database independent.
What do you need the total returned by the query for? if its pagination look into Will_paginate (Railscast) which can be extended with AJAX etc...
Try find_by_sql may that help.
Is #robots.size what you're looking for? Or Robot.count?
Otherwise, please clarify.
I think hakunin is right.
You can get no of row return by query by just chekcing the size of resulting array of query.
#robots = Robot.find_by_sql("Your sql")
or
#robots = Robot.find(:all , :conditions=>["your condiitons"] )
#robots.size or #robots.count