Typeorm top level and operator without using querybuilder - typeorm

How could I achieve the following query using TypeORM without the QueryBuilder. I know I could do this with .andWhere(), but will I be able to do this with just .find()
where (
("User"."name" ilike $1 or "User"."email" ilike $5)
and "User"."organizationId" in ($17, $18, $19)
)

No, this can't be achieved with repository pattern.
I have asked same questions here: TypeORM find where conditions AND OR chaining
You can check there what did I use for the solution.

Related

pass arguments to sql.squish

I want to use EXIST in my select request for having a "published" column depending of if the article was published in a book in a set of year.
So I do the following
p params[:years] # "2002"
p params[:years].is_a?(String) # true
Article.select(<<~SQL.squish, years: params[:years])
articles.*, EXISTS(
SELECT 1
FROM books
WHERE books.year IN (:years)
) AS published
SQL
But it gives me the follwing error
Unsupported argument type: Hash. Construct an Arel node instead
and if I try like this
p params[:years] # "2002"
p params[:years].is_a?(String) # true
Article.select(<<~SQL.squish)
articles.*, EXISTS(
SELECT 1
FROM books
WHERE books.year IN (#{params[:years]})
) AS published
SQL
PG::UndefinedFunction: ERROR: operator does not exist: character varying = bigint
WHERE books.year IN (2022)
But params[:years] is a string I don't know how I can do what I want and I don't understand both of errors.
EDIT: if I use single quote like this
p params[:years] # "2002"
p params[:years].is_a?(String) # true
Article.select(<<~SQL.squish)
articles.*, EXISTS(
SELECT 1
FROM books
WHERE books.year IN ('#{params[:years]}')
) AS published
SQL
It work for a single value but if params[:years] is an array it work but the output isn't correct, if I have articles in a book in 2003 it will set published at false
p params[:years] # ["2002", "2003"]
p params[:years].is_a?(String) # false
Article.select(<<~SQL.squish)
articles.*, EXISTS(
SELECT 1
FROM books
WHERE books.year IN ('#{params[:years]}')
) AS published
SQL
The Object.select method in ActiveRecord doesn't support sanitised insertion of placeholders in the way that, for example, .where does. And that's why you're getting the error you're getting – select is expecting a list of fields, but one of your arguments is a Hash.
One way to get the functionality you're looking for is, as the error message suggests, to use Arel (if you're not familiar with it, think of Arel as the "building blocks" that ActiveRecord uses internally to construct its SQL queries). Max's answer is a good translation of your query into Arel.
Alternatively, you can sanitize your own SQL in the same way that other parts of ActiveRecord do. Splitting this up into the SQL parsing and the select statement for clarity:
sql = Article.sanitize_sql([<<~SQL, year: params[:years]])
articles.*, EXISTS(
SELECT 1
FROM books
WHERE books.year IN (:years)
) AS published
SQL
Article.select(sql)
I'd say that hand sanitising your SQL will get you over the stumbling block you're currently at, but if you're going to be doing similar types of operation all over the shop you'll benefit from understanding what Arel does and how to use it.
By interpolating the user input into a SQL query you're leaving yourself wide open for an SQL injection attack.
This is easy to prevent by using Arel to construct the query instead:
Article.select(
Article.arel_table[Arel.star],
Book.select(1)
.where(year: params[:years])
.arel
.exists
.as('published')
)
SELECT
"articles".*,
EXISTS (SELECT 1 FROM "books" WHERE "books"."year" IN (?, ?, ?)) AS published
FROM "articles"

MyBatis Dynamic SQL join on subquery

I want to do something like this in MyBatis Dynamic SQL:
SELECT id FROM foo
JOIN (SELECT foo_id ...) bar ON foo.id = bar.foo_id
WHERE ...
However, the join() function only accepts SqlTable as an argument.
Is it possible to join on a subquery with MyBatis Dynamic SQL? If so, how do I do it?
MyBatis Dynamic SQL doesn't support these types of sub-queries right now. I'll think about adding it.
What's your database?
Do you really need to explicitly use JOIN like this?
Can't you do it just ike this?
SELECT id FROM foo , (select foo_id...) bar
WHERE foo.id = bar.foo_id

How to convert a plain sql query with subqueries to use rails active record

I have tried converting this plain sql query to rails active record but I am unable to do so.
select vote_shares.election_year as vs_election_name,
vote_shares.party as vs_party,
(sum(vote_shares.party_seats)/totals.total)*100 AS vs
from pcdemographics INNER JOIN vote_shares on vote_shares.pc_id = pcdemographics.pc_id,
(
SELECT vote_shares.election_name, sum(vote_shares.party_seats) as total
FROM `pcdemographics`
INNER JOIN vote_shares on vote_shares.pc_id = pcdemographics.pc_id
GROUP BY `election_name`
) AS totals
where vote_shares.election_name=totals.election_name
group by vote_shares.party,vote_shares.election_name;
This is what I have tried
#vssubquery = Pcdemographic.select('vote_shares.election_name, sum(vote_shares.party_seats) as total').joins('INNER JOIN vote_shares on vote_shares.pc_id = pcdemographics.pc_id')
Pcdemographic.select("vote_shares.election_year as vs_election_year,
vote_shares.party as vs_party,
(sum(vote_shares.party_seats)/'#{totals.total}')*100 AS vs").from(#vssubquery,:totals)
.joins("INNER JOIN vote_shares on vote_shares.pc_id = pcdemographics.pc_id and vote_shares.election_name='#{totals.election_name}'")
My answer might not be what you hoped for but I recommend not using AR, use Sequel (http://sequel.jeremyevans.net/) instead. It uses the concept of Datasets which I don't think has any equivalent in AR.
Disclaimer: Nobody asked me to advertise for it. I used both AR and Sequel and I found that Sequel is much better to perform complex queries and avoid the N+1 problem.
Did you try find_by_sql method?

How do I optimize a select query in Activerecord?

I'm looking to see if there is a better way to write the following ActiveRecord query.
#posts = Post.select {|x| x.section.nil?}
What I'm doing with this query is searching through posts and just selecting the posts that no longer have sections associated and are left orphaned.
Is there a better way to do this? I'm using rails 3.2.
Thanks so much.
This should work:
Post.joins('left outer join sections on sections.id = posts.section_id').where('sections.id is null and posts.section_id is not null')
or in shorter way, using eager_load:
Post.eager_load(:section).where('sections.id is null and posts.section_id is not null')

executing query from ruby on rails the right way

I'm just beginning with ruby on rails and have a question regarding a bit more complex query. So far I've done simple queries while looking at rails guide and it worked really well.
Right now I'm trying to get some Ids from database and I would use those Ids to get the real objects and do something with them. Getting those is a bit more complex than simple Object.find method.
Here is how my query looks like :
select * from quotas q, requests r
where q.id=r.quota_id
and q.status=3
and r.text is not null
and q.id in
(
select A.id from (
select max(id) as id, name
from quotas
group by name) A
)
order by q.created_at desc
limit 1000;
This would give me 1000 ids when executing this query from sql manager. And I was thinking to obtain the list of ids first and then find objects by id.
Is there a way to get these objects directly by using this query? Avoiding ids lookup? I googled that you can execute query like this :
ActiveRecord::Base.connection.execute(query);
Assuming Quota has_many :requests,
Quota.includes(:requests).
where(status:3).
where('requests.text is not null').
where("quotas.id in (#{subquery_string_here})").
order('quotas.created_at desc').limit(1000)
I'm by no means an expert but most basic SQL functionality is baked into ActiveRecord. You might also want to look at the #group and #pluck methods for ways to eliminate the ugly string subquery.
Calling #to_sql on a relationship object will show you the SQL command it is equivalent to, and may help with your debugging.
I would use find_by_sql for this. I wouldn't swear that this is exactly right, but as I recall you can pretty much plonk an SQL statement into a find_by_sql and the resulting columns will be returned as attributes of an array of objects of the class you call it on:
status = 3
Quota.find_by_sql('
select *
from quotas q, requests r
where q.id=r.quota_id
and q.status= ?
and r.text is not null
and q.id in
(
select A.id from (
select max(id) as id, name
from quotas
group by name) A
)
order by q.created_at desc
limit 1000;', status)
If you come to Rails as someone used to writing raw SQL, you're probably better off using this syntax than stringing together a bunch of ActiveRecord methods - the result is the same, so it's just a matter of what you find more readable.
Btw, you shouldn't use string interpolation (i.e. #{variable} syntax) inside an SQL query. Use the '?' syntax instead (see my example) to avoid SQL injection potential.

Resources