Im trying to create a sql query dynamically with the following syntax:
Company.joins(:founder_persons)
.where("people.first_name like people[:first_name]", {people: {first_name: 'm%'}})
But running this on the rails console gives me TypeError: can't quote Array. Im guessing this is not how we use the where string? What's the right way to fix this error? Thanks.
One reason this error can occur is with a nested array used as SQL value.
Example:
Article.where(author: ['Jane', 'Bob'])
works, but:
Article.where(author: ['Jane', ['Bob']])
would give the error. A quick fix would be to run flatten on the array.
(Mentioning this since this page comes up when searching for the confusing error "Can't quote array".)
You could bind any value and then assign it, this way they should coincide in numbers, like:
Model.joins(:join_table)
.where('models.first_attribute LIKE ? AND models.second_attribute LIKE ?', value_for_first_attr, value_for_second_attr)
If using an array you should access each index you want to compare, or you can precede a splat *, and specify just one value, like:
Model.joins(:join_table)
.where('models.first_attribute LIKE ? AND models.second_attribute LIKE ?', *array_of_values)
Note although this way you're passing the "whole" array it should also coincide in size or numbers, otherwise it'd raise an ActiveRecord::PreparedStatementInvalid error depending if there are more or less elements than needed.
Related
I'm having an issue getting a query to work.
I'm essentially trying to write something like the following SQL, with the literal 5 replaced with a variable:
SELECT *
FROM "my_table"
WHERE 5 BETWEEN "my_table"."minimum" AND "my_table"."maximum"
This is what I have at the moment:
MyModel.where(
Arel::Nodes::Between.new(
my_variable, (MyModel.arel_table[:minimum]).and(MyModel.arel_table[:maximum])
)
)
Please ignore the way I am using arel_table, the actual query has multiple joins and is more complex, but this is the most minimum reproducible example I have to demonstrate the problem.
The error, as in the subject of the question is as follows:
undefined method `and' for #<Arel::Attributes::Attribute:0x00007f55e15514f8>
and method is for Arel::Nodes::Node i.e. MyModel.arel_attribute[:name].eq(Arel::Nodes::Quoted.new('engineersmnky')) This is an Arel::Nodes::Equality and you can chain with and.
That being said you can construct an Arel::Nodes::And for yourself via
Arel::Nodes::And.new([left,right])
Then we can pass this to the Between class like so
Arel::Nodes::Between.new(
Arel::Nodes::Quoted.new(my_variable),
Arel::Nodes::And.new([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
)
The Arel::Nodes::Quoted (also: Arel::Nodes.build_quoted(arg)) is not needed in your case since your my_variable is an Integer which can be visited and will be treated as an Arel::Nodes::SqlLiteral but I find it best to let arel decide how to handle the quoting in case your my_variable ends up being some other un-visitable Object
There are other ways to create a Between and other ways to create an And depending on what objects you are dealing with.
between is a Arel::Predication and these predications are available to Arel::Nodes::Attribute objects e.g.
MyModel.arel_table[:minimum].between([1,6])
and as mentioned is available to Arel::Nodes::Node and instances of this class provides a convenience method (create_and) for creating an And so we could do the following:
Arel::Nodes::Node.new.create_and([
MyModel.arel_table[:minimum],
MyModel.arel_table[:maximum]])
There are a number of other ways to hack this functionality together by using other Arel classes but this should get you headed in the right direction.
I am trying to use an if statement with a variable in my expression and I get no results. The variable works when I use the variable on it's own but when used with the if I get no results.
I have tried:
if(OrderQtr='Apr-Jun 2018',$(vAvgOrderCost),0)
if(OrderQtr='Apr-Jun 2018',sum($(vAvgOrderCost)),0)
sum($(vAvgOrderCost)if(OrderQtr='Apr-Jun 2018',0))
Nothing seems to work. Thanks
Variables in QlikView are used as a text replace feature, so be carefull. If your variable hold a value like 1,345 an expression like "if(OrderQtr='Apr-Jun 2018',$(vAvgOrderCost),0)" will be translated into "if(OrderQtr='Apr-Jun 2018',1,345,0)" which by itself will be a syntax error.
Something like :
Num(if(OrderQtr='Apr-Jun 2018','$(vAvgOrderCost)','0'))
would be a safe way to go.
the if() syntax should work like this if(test,true,false)
So looking at your examples I suspect this is what you are trying to do
sum(if(OrderQtr='Apr-Jun 2018',$(vAvgOrderCost),0))
I am new to rails. I am trying to figure out how to use model method inside the sum() sql function. I tried searching for the solution but couldn't find one. Here's the code snippet :
SUM(indents.total_payable_amount_paid) AS sum_comm_t_amount_payable_paid
I want to use method called total_payable_amount_paid defined inside indent model. But it always gives an error:
PGError: ERROR: column indents.total_payable_amount_paid does not exist.
So what's the solution for this problem? Thanks in advance!
The problem is that your SUM (which i assume it's in a query string) takes indents.total_payable_amount_paid as part of that string.
To avoid that you could use string interpolation to set the value you want, like this:
"SUM(#{indents.total_payable_amount_paid}) AS sum_comm_t_amount_payable_paid"
So, lets say indents.total_payable_amount_paid returns 250, then the above code will generate this string:
"SUM(250) AS sum_comm_t_amount_payable_paid"
But, using SUM will make no effect, since you are giving one value, so you can accomplish the same thing without it:
"#{indents.total_payable_amount_paid AS sum_comm_t_amount_payable_paid"
#=> "250 AS sum_comm_t_amount_payable_paid"
This error showed up when I was trying to search from a range of date.
This is my model:
def self.search(search)
if search
#policies = Policy.find_by_sql("acct_ent_date IN ?", start_date..end_date)
else
limit(10)
end
end
Just to help out anyone else coming here: If you want to use query params with find_by_sql, you need to put all the arguments into an array, like this:
Policy.find_by_sql(["acct_ent_date IN ?", start_date..end_date])
I've never actually seen passing a range as a query parameter, so I can't comment on that, but in general the "undefined method `value_for_database'" error comes from not wrapping the arguments in an array.
You rarely need to drop down to writing raw SQL in rails (e.g. using the find_by_sql method) - especially for such a simple query as this.
Instead, you can just write the following and ActiveRecord will correctly convert it to valid SQL syntax for you:
# If you are looking for a list of all matching entries:
Policy.where(acct_ent_date: start_date..end_date)
# If you only wish to fetch the FIRST matching entry:
Policy.find_by(acct_ent_date: start_date..end_date)
This will generate SQL like the following:
SELECT `policies`.* FROM `policies` WHERE (`policies`.`acct_ent_date` BETWEEN xxxxx AND yyyyy)
The key problem with your original (raw SQL) code is that you are using WHERE IN syntax - which is really just shorthand for multiple OR conditions. This does not make sense to use with a Range (start_date..end_date) object, as this is not a discrete list (i.e. an Array).
If you were to attempt to convert your object into an array, you would see an error something like this:
(start_date..end_date).to_a # => TypeError: can't iterate from Time
Here is the single line from one of my functions to test if any objects in my array have a given property with a matching value
Return ((From tag In DataCache.Tags Where (tag.FldTag = strtagname) Select tag).Count = 1)
WHERE....
DataCache.Tags is an array of custom objects
strtagname = "brazil"
and brazil is definitely a tag name stored within one of the custom objects in the array.
However the function continually returns false.
Can someone confirm to me that the above should or should not work.
and if it wont work can someone tell me the best way to test if any of the objects in the array contain a property with a specific value.
I suppose in summary I am looking for the equivalent of a SQL EXISTS statement.
Many thanks in hope.
Your code is currently checking whether the count is exactly one.
The equivalent of EXISTS in LINQ is Any. You want something like:
Return DataCache.Tags.Any(Function(tag) tag.FldTag = strtagname)
(Miraculously it looks like that syntax may be about right... it looks like the docs examples...)
Many Thanks for the response.
Your code did not work. Then I realised that I was comparing to an array value so it would be case sensitive.
However glad I asked the question, as I found a better way than mine.
Many thanks again !