我在这里,因为我一直在寻找一些查询,可以帮助找到现有的记录与重叠的项目范围,但我找不到任何东西。假设我有一个名为Cart
的模型。购物车具有以下属性:item_min
和item_max
,其中item_max
可为空,当为空时将被视为无限。在我的模型中,我想添加一个验证,这样就不会保存具有重叠项目范围的记录。
我已经创建了一个查询,但它并不适用于我的所有测试用例:
saved cart: item_min: 2, item_max: nil
try to save cart: `item_min: 1, item_max: 1` VALID
try to save cart: `item_min: 1, item_max: 2` VALID
try to save cart: `item_min: 1, item_max: 6` INVALID
try to save cart: `item_min: 4, item_max: 7` INVALID
try to save cart: `item_cart: 4, item_max: nil` INVALID
saved cart: `item_min: 2, item_max: 7`
try to save `cart: item_min: 1, item_max: 1` VALID
try to save cart: `item_min: 8, item_max: 10` VALID
try to save cart: `item_min: 8, item_max: nil` VALID
try to save cart: `item_min: 1, item_max: 2` INVALID
try to save cart: `item_min: 1, item_max: 8` INVALID
try to save cart: `item_min: 1, item_max: 5` INVALID
try to save cart: `item_min: 5, item_max: 10` INVALID
try to save cart: `item_min: 3, item_max: 5` INVALID
try to save cart: `item_min: 1, item_max: nil` INVALID
我创建了以下查询:
def validate_item_count_range
if item_count_max.nil?
overlap_carts = Cart.where(item_count_max: nil)
else
overlap_carts = Cart.where(
"item_count_min >= ? AND item_count_max <= ?", item_count_min, item_count_max,
).or(
Cart.where(
"item_count_min <= ? AND item_count_max IS NULL", item_count_min,
),
)
end
errors.add(:item_count_min, "overlaps with existing carts") if overlap_carts.present?
end
然而,这种验证并不适用于我的所有测试用例。你能帮我改进我的查询,这样我的测试用例就可以通过了吗?
顺便说一句,我正在使用PostgreSQL
1条答案
按热度按时间vc6uscn91#
使用
Range#overlaps?
、ActiveRecord::Calculations#pluck
和Array#any?
没有特殊的SQL查询
无限范围有一个明确的开始值,但结束值为
nil
。您可以忽略此nil
这样的范围包括从开始值开始的所有值
当然,这种方法适用于通常的范围,
正如Jad在评论中所写的那样,如果有百万条记录,这种数组验证的性能将很低。使用built-in ranges in PostgreSQL进行SQL查询的想法:
RDBMS将优化这样的查询。这将是更有效的比操作与巨大的阵列
[]
在这个查询中表示包含的下限和上限(默认情况下上限是排他性的)使用
NULL
意味着范围是无限的&&
操作员检查重叠