how to embed order by string in hql in grails for sorting? - grails

In grails 2 i used to use the following hql
def sortp = ""
if(params.sort){
sortp = "order by r.${params.sort} ${params.order}"
}
def allRegsData = RaceRegistration.executeQuery("select r.id, r.bibLabelPrinted, r.raceParticipant.bibNumber, r.bibLabelCollected, r.raceParticipant.firstName,r.raceParticipant.lastName,r.raceParticipant.gender,r.race.name, rt.name, r.raceParticipant.ageDate, ad.genderOption, ad.minAge, ad.maxAge, sd.name, sm.encodedMark, p.name, p.abbreviation, ps.name, r.dateCreated, r.status, r.race.id, re.invoice.id, io.status, r.notes from InventoryOrder io inner join io.product p inner join io.productSize ps right outer join io.registration r left outer join r.registrationEntry re left outer join r.specialDivision sd left outer join r.ageDivision ad left outer join r.team rt left outer join r.seedMark sm where r.compositeEvent = ? ${sortp}", [raceGroup]);
I am now using grails 4 and it seems i can no longer use this way of embedding sortp string.
It throws the error
Unsafe query [select r.id, r.bibLabelPrinted, r.raceParticipant.bibNumber, r.bibLabelCollected, r.raceParticipant.firstName,r.raceParticipant.lastName,r.raceParticipant.gender,r.race.name, rt.name, r.raceParticipant.ageDate, ad.genderOption, ad.minAge, ad.maxAge, sd.name, sm.encodedMark, p.name, p.abbreviation, ps.name, r.dateCreated, r.status, r.race.id, re.invoice.id, io.status, r.notes from InventoryOrder io inner join io.product p inner join io.productSize ps right outer join io.registration r left outer join r.registrationEntry re left outer join r.specialDivision sd left outer join r.ageDivision ad left outer join r.team rt left outer join r.seedMark sm where r.compositeEvent = ? ]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped.
i have tried this approach but it doesnt seem to sort
def allRegsData = RaceRegistration.executeQuery("select r.id, r.bibLabelPrinted, r.raceParticipant.bibNumber, r.bibLabelCollected, r.raceParticipant.firstName,r.raceParticipant.lastName,r.raceParticipant.gender,r.race.name, rt.name, r.raceParticipant.ageDate, ad.genderOption, ad.minAge, ad.maxAge, sd.name, sm.encodedMark, p.name, p.abbreviation, ps.name, r.dateCreated, r.status, r.race.id, re.invoice.id, io.status, r.notes from InventoryOrder io inner join io.product p inner join io.productSize ps right outer join io.registration r left outer join r.registrationEntry re left outer join r.specialDivision sd left outer join r.ageDivision ad left outer join r.team rt left outer join r.seedMark sm where r.compositeEvent = :rg order by :s", [rg: raceGroup, s: 'r.' + params.sort + ' ' + params.order ]);
i appreciate any guide as to how to do the same in grails 4? Thanks!

thanks to Prudius from grails.slack.com
I had to change slightly how i form the string.
def sortp = ""
if(params.sort){
sortp = "order by r.${params.sort} ${params.order}"
}
def q = "select r.id, r.bibLabelPrinted, r.raceParticipant.bibNumber, r.bibLabelCollected, r.raceParticipant.firstName,r.raceParticipant.lastName,r.raceParticipant.gender,r.race.name, rt.name, r.raceParticipant.ageDate, ad.genderOption, ad.minAge, ad.maxAge, sd.name, sm.encodedMark, p.name, p.abbreviation, ps.name, r.dateCreated, r.status, r.race.id, re.invoice.id, io.status, r.notes from InventoryOrder io inner join io.product p inner join io.productSize ps right outer join io.registration r left outer join r.registrationEntry re left outer join r.specialDivision sd left outer join r.ageDivision ad left outer join r.team rt left outer join r.seedMark sm where r.compositeEvent = :rg "
q <<= sortp
def allRegsData = RaceRegistration.executeQuery(q, [rg: raceGroup]);
this further helped.
Groovy literal StringBuilder/StringBuffer

Related

Trying to fetch data from table with good performance

I am trying to fetch customer and owner data
customer
|cnumber |id |
|080204220 |32859471000|
|907501981|6029151000|
role
|id|type|
|32859471000|owner|
|6029151000|customer|
result set
id|number|owner number|type|
|32859471000|080204220 |080204220 | owner
|6029151000|907501981|080204220 |customer
query
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
This query gives proper result, but left outer join with same tables may cause impact on performance, is there any other way to achieve this?
I would prefer you to go with this only.
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
As far as I can get the logic, you need to display an "owner"-customer among all of the others.
Since there is only one owner in the example data, I'd do it using the "cross join" (cartesian join)
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
cross join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id where r.roletype='owner') sub
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';

How to only join on numeric values

Right now I have:
select
a.id
b.colone
b.coltwo
from tablea a
left join tableb b on b.id = a.id
I'm getting the "numeric value not recognized" error because one value from b.id is not numeric. How do I join results from tableb to tablea just omitting the non-numeric value/row? Or how else can I bypass this error? Using snowflake.
Thank you!
You can use TRY_TO_NUMBER():
select
a.id
b.colone
b.coltwo
from tablea a
left join tableb b on TRY_TO_NUMBER(b.id) = a.id

How to write left join on( ~~ and ~~). not left join on ~~ where ~~ in ActiveRecord

I always see like
joins(~~~).where(~~~~)
How to write like
SQL join: where clause vs. on clause
SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
AND Orders.ID = 12345
ActiveRecord in rails.
You can do your query like:
Order.joins("LEFT JOIN order_lines ON order_lines.order_id=orders.id
AND orders.id = 12345")

Why is Arel dropping the 'left outer join' when it builds SQL?

I'm trying to build the following query in Arel:
select a.* from (first nested query) as a
left outer join (second nested query) as b
on a.id = b.id
where b.id is null;
This is my best attempt:
query = a.
project(a[Arel.star]).
from(a_nested_sql).
join(b_nested_sql, Arel::Nodes::OuterJoin).
on(a[:id].eq(b[:id])).
where(b[:id].eq(nil))
But it keeps dropping the 'left outer join' producing invalid SQL:
select a.* from (first nested query) as a
(second nested query) as b
on a.id = b.id
where b.id is null;
What am I doing wrong?
After a lot of experimenting, this did the trick:
query = a_table.
project(a_table[Arel.star]).
from(a_nested_sql).
join(
b_table.join(b_nested_sql).join_sources,
Arel::Nodes::OuterJoin
).
on(a_table[:id].eq(b_table[:id])).
where(b_table[:id].eq(nil))
Not really sure why as I don't really understand what join_sources does.

Where clause filtering by "ANY" - What does this means?

I'm trying to understand why I don't receive any records on a ruby on rails app using postgresql. This is the SQL query that is being executed:
SELECT g.program_id, g.title,
COALESCE(COUNT(pr), 0) AS ac, g.default
FROM groups AS g
LEFT OUTER JOIN memberships AS m ON m.group_id = g.id
LEFT OUTER JOIN progresses AS pr ON m.id = pr.participant_id
AND (pr.status = 'completed')
WHERE g.program_id = ANY(#1)
GROUP BY g.id
ORDER BY g.program_id, g.position, g.id
My question is: what does the ANY(#1) means?
Please have pacience, as I'm a ruby/rails/postgresql newbie.
Thanks!
Update: added some aditional code. Plese don't ident the query below as it is already idented above.
class StatsComponents::CompletedActivitiesPerGroupStats
include StatsComponent::Interface
GROUP_ACTIVITIES = <<-SQL
g.program_id, g.title, COALESCE(COUNT(pr), 0) AS ac, g.default
FROM groups AS g
LEFT OUTER JOIN memberships AS m ON m.group_id = g.id
LEFT OUTER JOIN progresses AS pr ON m.id = pr.participant_id
AND (pr.status = 'completed')
WHERE g.program_id = ANY(#1)
GROUP BY g.id
ORDER BY g.program_id, g.position, g.id
SQL
def generate
...
It selects records where g.program_id has a value existing in the array returned by #1 request, which they set as a query parameter (for example SELECT...) somewhere further in the program.
You can equally use SOME(#1) here.
By the way strictly speaking, this isn't a sql query. While there is no sql.execute or something like that, it's just a multiline string assignment.

Resources