存储过程使用存储在数据库列中的动态SQL语句



我有一个名为Coupon的表。

该表有一个名为query的列,其中包含一个字符串。

query字符串中有一些为where语句格式化的逻辑条件。例如:

coupon1.query
=> " '/hats' = :url "
coupon2.query
=> " '/pants' = :url OR '/shoes' = :url "

我想编写一个存储过程,它以两个参数作为输入:一个Couponid列表和一个变量(在本例中,是当前URL(。

我希望该过程从每个Coupon中查找query列的值。然后,它应该在where语句中运行该字符串,插入我的另一个参数(当前url(,然后返回任何匹配的Couponid。

以下是我在上面两张优惠券的情况下期望程序的表现。

Example 1: 
* Call procedure with ids for coupon1 and coupon2, with @url = '/hats'
* Expect coupon1 to be returned.
Example 2: 
* Call procedure with ids for coupon1 and coupon2, with @url = '/pants'
* Expect coupon2 to be returned.
Example 3: 
* Call procedure with ids for coupon1 and coupon2, with @url = '/shirts'
* Expect no ids returned. URL does not match '/hats' for coupon1, and doesn't match '/pants or /shoes' for coupon2. 

在ActiveRecord中测试这些很容易。这里只是示例1。

@url = '/hats'
@query = coupon1.query 
# "'/hats' = :url"
Coupon.where(@query, url: @url).count
=> 2   
# count is non-zero number because the query matches the url parameter. 
# Coupon1 passes, its id would be returned from the stored procedure.
'/hats' == '/hats'
@query = coupon2.query 
# " '/pants' = :url OR '/shoes' = :url "
Coupon.where(@query, url: @url).count
=> 0
# count is 0 because the query does not match the url parameter. 
# Coupon2 does not pass, its id would not be returned from the stored procedure.
'/pants' != '/hats', '/shoes' != '/hats'

你可以把它写成一个循环(我用activerecord在ruby on rails中(,但我需要一些性能更好的东西——我可能有很多优惠券,所以我不能直接用循环检查每个优惠券。查询包含复杂的AND/OR逻辑,所以我也不能只与url列表进行比较。但这里有一些循环的代码,它本质上就是我试图翻译成存储过程的内容。

# assume coupon1 has id 1, coupon2 has id 2
@coupons = [coupon1, coupon2]
@url = '/hats'
@coupons.map do |coupon|
if Coupon.where(coupon.query, url: @url).count > 0
coupon.id
else
nil
end
end
=> [1, nil]

好吧,我一直在思考这个问题。

总体情况:

A。您有一个想要搜索的@url,以便在许多潜在的Coupons中找到匹配项

B。coupon的URL可能与@url匹配

如果这是问题的真实程度,我认为你真的把事情搞得太复杂了。

coupon1.query
=> ["/hats"]
coupon2.query
=> ["/pants", "/shoes"]
@url = '/hats'
Coupon.where('FIND_IN_SET(:url, query) <> 0')

或者类似的事情,我自己不是mySQL用户。

然而,这是非常有可能实现的,甚至可能有更好的ActiveRecord查询方式。


更新

好吧,我错过了什么。我实际上无法在控制台中复制这个。

@url = '/hats'
@query = coupon1.query 
# "'/hats' = :url"
Coupon.where(@query, url: @url).count
> SELECT * FROM 'coupons' WHERE ( '/hats' = '/hats' )

正如您从select语句中看到的,这将始终返回所有记录。与编写SELECT * FROM 'coupons' WHERE ( true )相同

您实际上是如何执行有效查询的?

很抱歉在我的回答中发布了这个,我想要良好的格式。

如果我这里有什么问题,也许我们需要把它转移到聊天室。

我想你的名声刚好够我邀请你去一个房间。


更新2

由于您必须分别将@query与每条记录进行比较,我认为您必须循环。

但是,我认为您不需要使用Coupon.where来实现这一点,因为您一次只比较一条记录。

@coupons.map do |coupon|
# don't bother putting nil in the array
next unless coupon.query == @url

coupon.id
end

然而,你最初的问题是关于缩放时的性能,你知道你不会用循环来解决这个问题。

也许是JSONB而不是String,这样您就可以实际执行一些SQL了。

但是,即使有了JSONB,这仍然很复杂,因为需要对您的条件进行适当的评估。

{
"url": {
"AND": ["/hats", "/shoes"],
"OR": ["/pants"]
},
"logged_in": true,
"is_gold_member": false
}
{
"logged_in": false,
"url": "/hats"
}
{
"url": {
"OR": ["/pants", "/shoes"]
}
}

最终,我认为您使用query属性所做的工作将继续成为您的绊脚石。这很聪明,但并不简单。

如果它是我的应用程序,我想我会重新考虑我的用例,并尝试找到一种不同的策略,以更符合实际的方式将特定的coupons映射到特定的参数。

相关内容

  • 没有找到相关文章

最新更新