Skip to content

Commit 01e6949

Browse files
committed
Merge pull request #549 from iaddict/master
Fix ordering on an aggregate in MSSQL
2 parents f54152f + da90328 commit 01e6949

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

lib/arjdbc/mssql/limit_helpers.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module LimitHelpers
44

55
# @private
66
FIND_SELECT = /\b(SELECT(\s+DISTINCT)?)\b(.*)/mi
7+
FIND_AGGREGATE_FUNCTIONS = /AVG|COUNT|COUNT_BIG|MAX|MIN|SUM|STDDEV|STDEVP|VAR|VARP/
78

89
module SqlServerReplaceLimitOffset
910

@@ -28,8 +29,10 @@ def replace_limit_offset!(sql, limit, offset, order)
2829
# 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.
2930
# 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
3031
if rest_of_query.downcase.include?('group by')
31-
if order.count(',') == 0
32-
order.gsub!(/ORDER BY (.*)/, 'ORDER BY MIN(\1)')
32+
if order.match(/^ORDER +BY +(#{FIND_AGGREGATE_FUNCTIONS})\(/i)
33+
# do nothing
34+
elsif order.count(',') == 0
35+
order.gsub!(/ORDER +BY +([^\s]+)(\s+ASC|\s+DESC)?/i, 'ORDER BY MIN(\1)\2')
3336
else
3437
raise('Only one order condition allowed.')
3538
end

test/db/mssql/limit_offset_test.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,24 @@ def test_limit_with_group_by
182182
assert_equal ['three', 'four'], ships.map(&:name)
183183
end if ar_version('3.0')
184184

185+
def test_limit_with_group_by_and_aggregate_in_order_clause
186+
%w( one two three four five six seven eight ).each_with_index do |name, i|
187+
LongShip.create!(:name => name, :width => (i+1)*10)
188+
end
189+
190+
ships = LongShip.select(:name).group(:name).limit(2).order('width').all
191+
assert_equal ['one', 'two'], ships.map(&:name)
192+
193+
ships = LongShip.select(:name).group(:name).limit(2).order('width DESC').all
194+
assert_equal ['eight', 'seven'], ships.map(&:name)
195+
196+
ships = LongShip.select(:name).group(:name).limit(2).order('MAX(width)').all
197+
assert_equal ['one', 'two'], ships.map(&:name)
198+
199+
ships = LongShip.select(:name).group(:name).limit(2).order('MAX(width) DESC').all
200+
assert_equal ['eight', 'seven'], ships.map(&:name)
201+
end if ar_version('3.0')
202+
185203
def test_select_distinct_with_limit
186204
%w(c a b a b a c d c d).each do |name|
187205
LongShip.create!(:name => name)

0 commit comments

Comments
 (0)