Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
0e8d4edd
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
0e8d4edd
编写于
7月 24, 2017
作者:
R
Rafael França
提交者:
Rafael Mendonça França
7月 24, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Merge pull request #29848 from kamipo/fix_distinct_count_with_order_and_limit
Fix `COUNT(DISTINCT ...)` with `ORDER BY` and `LIMIT`
上级
39753133
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
88 addition
and
47 deletion
+88
-47
activerecord/CHANGELOG.md
activerecord/CHANGELOG.md
+4
-0
activerecord/lib/active_record/collection_cache_key.rb
activerecord/lib/active_record/collection_cache_key.rb
+1
-1
activerecord/lib/active_record/relation.rb
activerecord/lib/active_record/relation.rb
+4
-0
activerecord/lib/active_record/relation/calculations.rb
activerecord/lib/active_record/relation/calculations.rb
+20
-12
activerecord/test/cases/calculations_test.rb
activerecord/test/cases/calculations_test.rb
+24
-0
activerecord/test/models/account.rb
activerecord/test/models/account.rb
+34
-0
activerecord/test/models/company.rb
activerecord/test/models/company.rb
+1
-34
未找到文件。
activerecord/CHANGELOG.md
浏览文件 @
0e8d4edd
*
Fix
`COUNT(DISTINCT ...)`
with
`ORDER BY`
and
`LIMIT`
to keep the existing select list.
*Ryuta Kamizono*
*
Fix
`unscoped(where: [columns])`
removing the wrong bind values
When the `where` is called on a relation after a `or`, unscoping the column of that later `where`, it removed
...
...
activerecord/lib/active_record/collection_cache_key.rb
浏览文件 @
0e8d4edd
...
...
@@ -14,7 +14,7 @@ def collection_cache_key(collection = all, timestamp_column = :updated_at) # :no
column
=
"
#{
connection
.
quote_table_name
(
collection
.
table_name
)
}
.
#{
connection
.
quote_column_name
(
timestamp_column
)
}
"
select_values
=
"COUNT(*) AS
#{
connection
.
quote_column_name
(
"size"
)
}
, MAX(%s) AS timestamp"
if
collection
.
limit_value
||
collection
.
offset_value
if
collection
.
has_limit_or_offset?
query
=
collection
.
spawn
query
.
select_values
=
[
column
]
subquery_alias
=
"subquery_for_cache_key"
...
...
activerecord/lib/active_record/relation.rb
浏览文件 @
0e8d4edd
...
...
@@ -646,6 +646,10 @@ def empty_scope? # :nodoc:
@values
==
klass
.
unscoped
.
values
end
def
has_limit_or_offset?
# :nodoc:
limit_value
||
offset_value
end
protected
def
load_records
(
records
)
...
...
activerecord/lib/active_record/relation/calculations.rb
浏览文件 @
0e8d4edd
...
...
@@ -111,7 +111,7 @@ def sum(column_name = nil)
def
calculate
(
operation
,
column_name
)
if
has_include?
(
column_name
)
relation
=
construct_relation_for_association_calculations
relation
=
relation
.
distinct
if
operation
.
to_s
.
downcase
==
"count"
relation
.
distinct!
if
operation
.
to_s
.
downcase
==
"count"
relation
.
calculate
(
operation
,
column_name
)
else
...
...
@@ -194,8 +194,13 @@ def perform_calculation(operation, column_name)
if
operation
==
"count"
column_name
||=
select_for_count
column_name
=
primary_key
if
column_name
==
:all
&&
distinct
distinct
=
nil
if
column_name
=~
/\s*DISTINCT[\s(]+/i
if
column_name
==
:all
if
distinct
&&
!
(
has_limit_or_offset?
&&
order_values
.
any?
)
column_name
=
primary_key
end
elsif
column_name
=~
/\s*DISTINCT[\s(]+/i
distinct
=
nil
end
end
if
group_values
.
any?
...
...
@@ -222,7 +227,7 @@ def operation_over_aggregate_column(column, operation, distinct)
def
execute_simple_calculation
(
operation
,
column_name
,
distinct
)
#:nodoc:
column_alias
=
column_name
if
operation
==
"count"
&&
(
limit_value
||
offset_value
)
if
operation
==
"count"
&&
has_limit_or_offset?
# Shortcut when limit is zero.
return
0
if
limit_value
==
0
...
...
@@ -361,16 +366,19 @@ def select_for_count
end
def
build_count_subquery
(
relation
,
column_name
,
distinct
)
column_alias
=
Arel
.
sql
(
"count_column"
)
subquery_alias
=
Arel
.
sql
(
"subquery_for_count"
)
relation
.
select_values
=
[
if
column_name
==
:all
distinct
?
table
[
Arel
.
star
]
:
Arel
.
sql
(
"1"
)
else
column_alias
=
Arel
.
sql
(
"count_column"
)
aggregate_column
(
column_name
).
as
(
column_alias
)
end
]
aliased_column
=
aggregate_column
(
column_name
==
:all
?
1
:
column_name
).
as
(
column_alias
)
relation
.
select_values
=
[
aliased_column
]
subquery
=
relation
.
arel
.
as
(
subquery_alias
)
subquery
=
relation
.
arel
.
as
(
Arel
.
sql
(
"subquery_for_count"
))
select_value
=
operation_over_aggregate_column
(
column_alias
||
Arel
.
star
,
"count"
,
false
)
sm
=
Arel
::
SelectManager
.
new
relation
.
engine
select_value
=
operation_over_aggregate_column
(
column_alias
,
"count"
,
distinct
)
sm
.
project
(
select_value
).
from
(
subquery
)
Arel
::
SelectManager
.
new
(
subquery
).
project
(
select_value
)
end
end
end
activerecord/test/cases/calculations_test.rb
浏览文件 @
0e8d4edd
...
...
@@ -241,6 +241,30 @@ def test_apply_distinct_in_count
end
end
def
test_distinct_count_with_order_and_limit
assert_equal
4
,
Account
.
distinct
.
order
(
:firm_id
).
limit
(
4
).
count
end
def
test_distinct_count_with_order_and_offset
assert_equal
4
,
Account
.
distinct
.
order
(
:firm_id
).
offset
(
2
).
count
end
def
test_distinct_count_with_order_and_limit_and_offset
assert_equal
4
,
Account
.
distinct
.
order
(
:firm_id
).
limit
(
4
).
offset
(
2
).
count
end
def
test_distinct_joins_count_with_order_and_limit
assert_equal
3
,
Account
.
joins
(
:firm
).
distinct
.
order
(
:firm_id
).
limit
(
3
).
count
end
def
test_distinct_joins_count_with_order_and_offset
assert_equal
3
,
Account
.
joins
(
:firm
).
distinct
.
order
(
:firm_id
).
offset
(
2
).
count
end
def
test_distinct_joins_count_with_order_and_limit_and_offset
assert_equal
3
,
Account
.
joins
(
:firm
).
distinct
.
order
(
:firm_id
).
limit
(
3
).
offset
(
2
).
count
end
def
test_should_group_by_summed_field_having_condition
c
=
Account
.
group
(
:firm_id
).
having
(
"sum(credit_limit) > 50"
).
sum
(
:credit_limit
)
assert_nil
c
[
1
]
...
...
activerecord/test/models/account.rb
0 → 100644
浏览文件 @
0e8d4edd
# frozen_string_literal: true
class
Account
<
ActiveRecord
::
Base
belongs_to
:firm
,
class_name:
"Company"
belongs_to
:unautosaved_firm
,
foreign_key:
"firm_id"
,
class_name:
"Firm"
,
autosave:
false
alias_attribute
:available_credit
,
:credit_limit
def
self
.
destroyed_account_ids
@destroyed_account_ids
||=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
end
# Test private kernel method through collection proxy using has_many.
def
self
.
open
where
(
"firm_name = ?"
,
"37signals"
)
end
before_destroy
do
|
account
|
if
account
.
firm
Account
.
destroyed_account_ids
[
account
.
firm
.
id
]
<<
account
.
id
end
end
validate
:check_empty_credit_limit
private
def
check_empty_credit_limit
errors
.
add
(
"credit_limit"
,
:blank
)
if
credit_limit
.
blank?
end
def
private_method
"Sir, yes sir!"
end
end
activerecord/test/models/company.rb
浏览文件 @
0e8d4edd
...
...
@@ -192,37 +192,4 @@ class SpecialClient < Client
class
VerySpecialClient
<
SpecialClient
end
class
Account
<
ActiveRecord
::
Base
belongs_to
:firm
,
class_name:
"Company"
belongs_to
:unautosaved_firm
,
foreign_key:
"firm_id"
,
class_name:
"Firm"
,
autosave:
false
alias_attribute
:available_credit
,
:credit_limit
def
self
.
destroyed_account_ids
@destroyed_account_ids
||=
Hash
.
new
{
|
h
,
k
|
h
[
k
]
=
[]
}
end
# Test private kernel method through collection proxy using has_many.
def
self
.
open
where
(
"firm_name = ?"
,
"37signals"
)
end
before_destroy
do
|
account
|
if
account
.
firm
Account
.
destroyed_account_ids
[
account
.
firm
.
id
]
<<
account
.
id
end
true
end
validate
:check_empty_credit_limit
private
def
check_empty_credit_limit
errors
.
add
(
"credit_limit"
,
:blank
)
if
credit_limit
.
blank?
end
def
private_method
"Sir, yes sir!"
end
end
require
"models/account"
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录