bun*_*ter 6 activerecord ruby-on-rails ruby-on-rails-3
莫因,
我偶然发现了ActiveRecord的不一致.
我试图在大表的两列中获取所有使用的值组合.第一个想法:
SELECT DISTINCT col1, col2 FROM table
Run Code Online (Sandbox Code Playgroud)
想象一下一个rails应用程序,它将餐饮组织为一个模型,每个Meal has_many :noodles
Each Noodle都有属性(因此DB表列)color和shape.我的目标是让所有当前组合的数量color和shape单个餐.
由于AR不提供我使用的"不同"方法
my_meal.noodles.select("distinct color, shape")
Run Code Online (Sandbox Code Playgroud)
得到(在rails console stdout中)一个6行输出的8个Noodle对象(分别是它们的String表示).但:
>> my_meal.noodles.select("distinct color, shape").count
=> 1606
Run Code Online (Sandbox Code Playgroud)
实际上my_meal包含1606面条.如果我将关系转换为数组并获取它的大小或使用.all.count结果是正确的.
所以我的问题是,为什么AR输出8个对象但是计算所有数据库线?
蒂姆,谢谢和最诚挚的问候
bun*_*ter 12
好的,感谢tadman让我朝着正确的方向前进.
我挖得更深(特别是在日志文件中),我发现的有点奇怪.
问题是由所选列的数量引起的.如果只选择一列并计算结果
my_meal.noodles.select("distinct color").count
Run Code Online (Sandbox Code Playgroud)
ActiveRecord创建以下SQL语句:
SELECT COUNT(distinct color) AS count_id FROM "NOODLES" WHERE ("NOODLES".meal_id = 295)
Run Code Online (Sandbox Code Playgroud)
如果一个选择两个或更多列并适用count它
my_meal.noodles.select("distinct color, shape").count
Run Code Online (Sandbox Code Playgroud)
ActiveRecord忘记了该select子句并创建:
SELECT COUNT(*) AS count_id FROM "NOODLES" WHERE ("NOODLES".meal_id = 295)
Run Code Online (Sandbox Code Playgroud)
这可能是正确的,因为(SQL)COUNT只允许一个或更少的列作为参数.在group之前添加一个count并且一切都很好:
my_meal.noodles.select("distinct color, shape").group("color, shape").count
SELECT COUNT(*) AS count_all, color, shape AS color_shape FROM "NOODLES" WHERE ("NOODLES".meal_id = 295) GROUP BY color, shape
Run Code Online (Sandbox Code Playgroud)
除此之外,AS color_shape它完全符合我的预期.但是......只有它返回:
>> my_meal.noodles.select("distinct color, shape").group("color, shape").count
=> {star=>309, circle=>111, spaghetti=>189, square=>194, triangle=>179, bowtie=>301, shell=>93, letter=>230}
>> my_meal.noodles.select("distinct color, shape").group("color, shape").count.class
=> ActiveSupport::OrderedHash
Run Code Online (Sandbox Code Playgroud)
这个奇怪的返回值是(除了依赖于DB的顺序)与结果和返回值相同
my_meal.noodles.group("shape").count
Run Code Online (Sandbox Code Playgroud)
结论:
正如这里所指出的,关系(可能是数学关系或关系关系)和ActiveRecord :: Relations之间仍然存在差距.
我可以看到尽可能经常地将结果压入模型的优点(至少在Rails应用程序的上下文中).
然而,实际关系不是几个操作相结合的结果,而是这些操作连接的结果.一般来说,ActiveRecord :: Relations的可连接性是一件好事,但有些设计决定是我无法遵循的.
如果你不能依赖于每个行动都返回一个新的合作关系的保证,那么它就失去了很大的诱惑力.
至于我的问题的解决方案,我将使用上述group解决方案和计数操作的某种脏的解决方法:
my_meal.noodles.select("distinct color, shape").group("color, shape").all.count
Run Code Online (Sandbox Code Playgroud)
这会将结果压缩到可接受的最小值,然后再将它们拉出数据库并创建昂贵的对象来计算它们.或者,可以使用手写SQL查询,但为什么有Rails并且不使用它,是吧?;-)
蒂姆,谢谢你的帮助
| 归档时间: |
|
| 查看次数: |
4927 次 |
| 最近记录: |