Skip to content

Commit cbb5a32

Browse files
Jeskokares
authored andcommitted
Handling of 'GROUP BY' and selected columns
1. Ensure correct queries if the rest_of_query contains a 'GROUP BY'. 2. Create a correct subquery if there's only one id column. Partially fixes #437
1 parent 1111522 commit cbb5a32

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

lib/arjdbc/mssql/limit_helpers.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,34 @@ def replace_limit_offset!(sql, limit, offset, order)
2424
rest_of_query = "#{from_table}.#{rest_of_query}"
2525
end
2626

27+
# Ensure correct queries if the rest_of_query contains a 'GROUP BY'. Otherwise the following error occurs:
28+
# ActiveRecord::StatementInvalid: ActiveRecord::JDBCError: Column 'users.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
29+
# SELECT t.* FROM ( SELECT ROW_NUMBER() OVER(ORDER BY users.id) AS _row_num, [users].[lft], COUNT([users].[lft]) FROM [users] GROUP BY [users].[lft] HAVING COUNT([users].[lft]) > 1 ) AS t WHERE t._row_num BETWEEN 1 AND 1
30+
if rest_of_query.downcase.include?('group by')
31+
if order.count(',') == 0
32+
order.gsub!(/ORDER BY (.*)/, 'ORDER BY MIN(\1)')
33+
else
34+
raise('Only one order condition allowed.')
35+
end
36+
end
37+
2738
if distinct # select =~ /DISTINCT/i
2839
order = order.gsub(/([a-z0-9_])+\./, 't.')
2940
new_sql = "SELECT t.* FROM "
3041
new_sql << "( SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, t.* FROM (#{select} #{rest_of_query}) AS t ) AS t"
3142
new_sql << " WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
3243
else
33-
new_sql = "#{select} t.* FROM "
44+
select_columns_before_from = rest_of_query.gsub(/FROM.*/, '').strip
45+
only_one_column = !select_columns_before_from.include?(',')
46+
only_one_id_column = only_one_column && (select_columns_before_from.ends_with?('.id') || select_columns_before_from.ends_with?('.[id]'))
47+
48+
if only_one_id_column
49+
# If there's only one id column a subquery will be created which only contains this column
50+
new_sql = "#{select} t.id FROM "
51+
else
52+
# All selected columns are used
53+
new_sql = "#{select} t.* FROM "
54+
end
3455
new_sql << "( SELECT ROW_NUMBER() OVER(#{order}) AS _row_num, #{rest_of_query} ) AS t"
3556
new_sql << " WHERE t._row_num BETWEEN #{start_row} AND #{end_row}"
3657
end

0 commit comments

Comments
 (0)