Remove parenthesis from SQLAlchemy select_from - sqlalchemy

I've got a PostgreSQL function that RETURNS TABLE, so it's valid to use it in a query like so:
SELECT col1, col2 FROM my_func(arg1 => :arg_1, arg2 => :arg_2)
I'm trying to create that with SQLAlchemy.
I've created the text() query object like so:
my_func = text("my_func(arg1 => :arg_1, arg2 => :arg_2)")
Set up bind params:
my_func = my_func.bindparams(bindparam("arg_1", value=arg_1), ...)
And because my function returns a table I've declared the columns on it too:
my_func = my_func.columns(col1=INTEGER, col2=TEXT)
Elsewhere in my code I am using this object to create the actual query:
select_query = select(my_func.c.col1).select_from(my_func).all()
I got this pattern from the tutorial on the text() object. But, when I go to render that final select() query, SQLAlchemy is coming up with SQL like this:
SELECT col1 FROM (my_func(arg1 => :arg_1, arg2 => :arg_2))
Which is a syntax error in PostgreSQL because of the extra parens around the FROM part of the clause, as if it were a complete subquery on its own.
As a workaround I changed the initial text() to do SELECT * FROM my_func(...) to make it into a proper subquery. That gets me working SQL but I wonder if I can get SQLAlchemy to treat the function as if it were a literal table name.

Related

Pattern matching using regex with Scala Anorm

I'm Using Scala(2.11) and playframework(2.3) and trying to run a query using a helper function to get results through pattern matching. The function is as follows
def resultsfunc() = {
val gradeRegex = "^Class 5\."
val currRegex = "\.NCERT$"
DB.withConnection{ implicit c =>
val filterQuery = SQL(
"""
select * from tbl_graphs
where graph_name REGEXP '{grade_regex}' and
graph_name REGEXP '{curr_regex}' and org_id = 4
""")
.on("grade_regex" -> gradeRegex,
"curr_regex" -> currRegex)
filterQuery().map{ graphRecord =>
new ResultObj(graphRecord[Long]("id"),
graphRecord[String]("name"))
}.toList
}
}
I don't get any errors but I get empty result even though there are multiple records that match the pattern. The same query works if I try to run in mysql workbench and when I tried to print filterQuery the arguments were also mapped correctly.
Should Pattern matching with regex must be carried out differently in Scala Anorm ?
It has absolutely nothing to do specifically with Anorm.
Make sure that executing manually the query with exactly the same data and parameter, you get result.
When using JDBC (even through Anorm), string parameter must not be quoted in the query statement (... '{grade_regex}' ...).
Since a long time, it's recommended to use Anorm interpolation (SQL"SELECT x FROM y WHERE z = ${v}") rather than SQL(..) function.

How do I set the placeholder for `knex`'s` raw` method to null?

I tried invoke bulk update query on mysql using knex raw method.
const ids:number[] = [1,2,3];
const values:string[] = ['apple', null, "orange"]
knex('testtable').raw(
`
UPDATE
TEST_TABLE
SET
COL1 = ELT(FIELD(id, :searchIds), :searchValues),
UPDATE_DATE = NOW()
WHERE ID IN (:searchIds)
`,
{ searchIds: ids, searchValues: values },
);`enter code here`
However, the intended result was not obtained.
This is because values contains a string and null, but theraw method's placeholders do not allow nulls.
Please tell me ,How do I set null to placeholder?
Binding array of values in knex doesn't work like that. SQL has multiple type of arrays, so those cannot be mapped to SQL unambiguous manner.
In docs: https://knexjs.org/#Raw-Bindings is an example how to pass arrays of values to knex.
const myArray = [1,2,3]
knex.raw(
`select * from users where id in (${myArray.map(() => '?').join(',')})`,
[...myArray]
);
In this case using named bindings pretty much impossible (actually named bindings are converted to positional bindings inside knex so there wont be even performance hit because of that).

Rails SQL query on unknown (dynamic) number of queries using LIKE

I have a Rails search form that performs a dynamic query. That is, the user enters a search like:
(hobby="skiing") OR (gender="male" AND hobby="jogging")
So, I don't know how many queries I will be searching by until runtime.
I parse the search query by converting it into a valid SQL query, so the above search would be converted to the following format:
query = "hobby LIKE ? OR (gender LIKE ? AND hobby LIKE ?)"
queries = ["skiing", "male", "jogging"]
For the following query:
where(query, queries)
However, the general syntax of the Rails search query is very limiting:
where(query, query_1, query_2, query_3)
I cannot replace the 'query_n' arguments with an array like I want to, without Rails throwing an error.
NoMethodError (undefined method `where' for ["a", "b", "c"]:Array)
Attempting to splat the array yields the same error:
where(query, *queries)
Again:
NoMethodError (undefined method `where' for ["a", "b", "c"]:Array)
So what can I do?
EDIT:
The full search function looks like this:
def self.search(search)
query = "%#{search}%"
if search
includes(:games, :jobs)
strngs = ["hobby = ? OR name = ? OR gender = ?", "dsfgdsfg", "dsgsdfgsd", "sdfsfsdf"]
.where(strngs)
What you'll want to do is pass an array as a single argument to where which contains both the query AND the dynamic values. For example:
where(["att_1 LIKE ? OR att_2 LIKE ?", "value1", "value2"])
If an array is passed as the first and only argument, then the first element of the array is treated as a template. The following array values are treated as the dynamic values for the query template.
For your example, instead of having two separate variables queries and query, combine them into one query variable:
# A single array with the query AND values
query = ["hobby LIKE ? OR (gender LIKE ? AND hobby LIKE ?)", "skiing", "male", "jogging"]
# Run the `where` with a single array as the argument
YourModel.where(query)
This will allow you to query the DB with an unknown number of values using LIKE.
For reference: Rails where() docs

EF6 Contains() works with only interned Strings

I want to filter my entity by name property. I use Contains() method. When I pass parameter as "E" it works but if I pass as variable it doesn't work.
Code is below :
if (!String.IsNullOrWhiteSpace(searchingModel.LanguageNameContains))
query = query.Where(n => n.Name.Contains(searchingModel.LanguageNameContains));
if (!String.IsNullOrWhiteSpace(searchingModel.LanguageCodeContains))
query = query.Where(n => n.Code.Contains(searchingModel.LanguageCodeContains));
return query;
Above example doesn't work. But if I write like this
if (!String.IsNullOrWhiteSpace(searchingModel.LanguageNameContains))
query = query.Where(n => n.Name.Contains("E"));
if (!String.IsNullOrWhiteSpace(searchingModel.LanguageCodeContains))
query = query.Where(n => n.Code.Contains("En"));
return query;
It works. I have debugged lots of times. I passed same parameters as variable and as constants. If I pass as constant it works but If I pass as variable it doesn't work. Curiously enough, The same code works MySql.Data.Entity 6.9.3 but now I am using 6.9.5 and it doesn't work. Is it a bug or my mistake ?
Generated SQL :
-when I pass parameter as variable:
SELECT
Extent1.Id,
Extent1.Code,
Extent1.Name
FROM Languages AS Extent1
WHERE Extent1.Name LIKE '%p__linq__0%'
-- p__linq__0: 'E' (Type = String, Size = 1)
-- Executing at 30.12.2014 22:30:40 +02:00
-- Completed in 0 ms with result: EFMySqlDataReader
when I pass as interned string :
SELECT
Extent1.Id,
Extent1.Code,
Extent1.Name
FROM Languages AS Extent1
WHERE Extent1.Name LIKE '%E%'
Second one returns rows but first one doesn't return any rows.

LINQ to SQL: Reuse lambda expression

I stumbled over some strange LINQ to SQL behaviour - can anybody shed some light on this?
I want to define a lambda expression and use it in my LINQ statement. The following code works fine:
[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
[...]
But when I try to use my lambda expression in a statement on an associated table
[...]
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
[...]
I get an exception:
Unsupported overload used for query operator 'Any'.
But, and this I don't get: It works fine when I put my lambda directly into the query:
[...]
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
[...]
WHY?!
Thanks.
Okay, here's the deal: dataContext.Table1s is of type IQueryable<T>. IQueryable<T> defines Where and Any methods that take a predicate of type Expression<Func<T, bool>>. The Expression<> wrapper is critical, as this is what allows LINQ to SQL to translate your lambda expression to SQL and execute it on the database server.
However, IQueryable<T> also includes IEnumerable<T>. IEnumerable<T> also defines Where and Any methods, but the IEnumerable version takes a predicate of type Func<T, bool>. Because this is a compiled function and not an expression, it can't be translated to SQL. As a result, this code...
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
...will pull EVERY record out of Table1s into memory, and then filter the records in memory. It works, but it's really bad news if your table is large.
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
This version has two lambda expressions. The second one, being passed directly into Where, is an Expression that includes a reference to a Func. You can't mix the two, and the error message you're getting is telling you that the call to Any is expecting an Expression but you're passing in a Func.
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
In this version, your inner lambda is automatically being converted to an Expression because that's the only choice if you want your code to be transformed into SQL by LINQ to SQL. In the other cases, you're forcing the lambda to be a Func instead of an Expression - in this case you're not, so it works.
What's the solution? It's actually pretty simple:
Expression<Func<Table1, bool>> lambda = x => x.Id > 1000;
Does Table1 refer to the same namespace? In the first example you're querying against the Table1 objects that are directly under dataContext, in the second example you're querying against the Table1 objects that is a property of the Table2 objects, and in the last example you're using a anonymous function which fix the issue.
I would look up the type of the Table1 objects that is a property of a Table2 object and compare it to a Table1 object that is connected directly to the dataContext. My guess is that they differ and your lambda expression is using the type of the object that is connected to the dataContext.