剖析数字范围
我正在尝试找出生成 WHERE 查询的最有效方法。我之前问过另一个类似的问题,但我会直奔主题。
给定一个数字范围的集合,即 1-1000
、1500-1600
,创建一个 mysql where 条件来选择这些值之间的记录非常简单。
即,您只需执行:
WHERE (lft BETWEEN 1 and 1000) OR (lft BETWEEN 1500-1600)
。但是,如果您还想合并 NOT BETWEEN 该怎么办?
例如,如果您定义多个规则,例如...
- ALLOW BETWEEN 1 - 1000
- ALLOW BETWEEN 1500 - 1600
- ALLOW BETWEEN 1250 - 1300
- DENY BETWEEN 25 - 50
如何合并这些规则以有效生成 WHERE 条件。 我希望在 WHERE 中剖析 ALLOW BETWEEN 1 - 1000
以在其中创建间隙。这样它就会变成 1-24
和 51-1000
。由于 DENY 规则是在第一个规则之后定义的,因此它“覆盖”前面的规则。
再举个例子, 假设您有
- ALLOW BETWEEN 5 - 15
- DENY BETWEEN 10 - 50
- ALLOW BETWEEN 45 - 60
然后我想生成一个 WHERE 条件,该条件允许我执行以下操作:
WHERE (lft BETWEEN 5 and 9) OR (lft BETWEEN 45 和 60)
。
注释(编辑)
- 此外,允许的最大范围是 1 - 5600000。(这将是“地球”)即。允许地球上的一切。
- 数字范围实际上是嵌套集合模型中的左侧值。这些不是唯一的键。 您可以在我之前提出的问题中了解我为什么要这样做。 https://stackoverflow.com/questions/ 6020553/generating-a-mysql- Between-where-condition-based-on-access-ruleset
- 关于我的数字范围的可能重要说明我可能不应该使用该示例我所做的示例,但关于数字范围的性质的一个重要注意事项是,范围实际上应该始终完全消耗或被先前的规则消耗。比如我用上面的例子,10-50允许,拒绝45-60。这在我的数据集中实际上不会发生。实际上,
允许 10-50
,那么 DENY 必须完全被该范围消耗,即 34-38。或者,完全消耗之前的规则。9-51
。这是因为范围实际上代表嵌套集合模型中的 lft 和 rgt 值,并且不能像我介绍的那样有重叠。
我在提出问题时没有想到提及这一点,但在看到下面的工作示例代码后,我可以看到这条注释实际上很重要。
(编辑示例 mysql 以包含 OR 而不是 AND,如下面的评论所示)
I'm trying to figure out the most efficient way to generate a WHERE query. I asked another question earlier, which was similar, but I will get right to the point on this one.
Given a collection of number ranges, ie 1-1000
, 1500-1600
it is quite simple to create a mysql where condition to select records which are between these values.
ie, you would just do:
WHERE (lft BETWEEN 1 and 1000) OR (lft BETWEEN 1500-1600)
. However, what if you wanted to incorporate a NOT BETWEEN as well.
For example, if you define several rules, like...
- ALLOW BETWEEN 1 - 1000
- ALLOW BETWEEN 1500 - 1600
- ALLOW BETWEEN 1250 - 1300
- DENY BETWEEN 25 - 50
How can I merge these rules in order to efficiently generate a WHERE condition.
I would like the WHERE to dissect the ALLOW BETWEEN 1 - 1000
in order to create a gap in it. So that it would become 1-24
and 51-1000
. Because the DENY rule is defined after the first rule, it "overwrites" the previous rules.
As another example,
Say that you have
- ALLOW BETWEEN 5 - 15
- DENY BETWEEN 10 - 50
- ALLOW BETWEEN 45 - 60
Then I would like to generate a WHERE condition which would allow me to do:
WHERE (lft BETWEEN 5 and 9) OR (lft BETWEEN 45 and 60)
.
Notes (Edits)
- Also, the maximum range that would ever allowed is 1 - 5600000. (Which would be 'Earth') ie. Allow everything on Earth.
- The number ranges are actually the LEFT values in a NESTED SET MODEL. These aren't unique keys.
You can read why I want to do this in this question I asked earlier.
https://stackoverflow.com/questions/6020553/generating-a-mysql-between-where-condition-based-on-an-access-ruleset - Possible important note on my number ranges I maybe shouldn't have used the sample example which I did, but one important note about the nature of the number ranges is that, the ranges should actually always entirely consume or be consumed by a previous rule. For example, I used the example above, 10-50 allow, and deny 45-60. This wouldn't actually ever happen in my data set. It would actually be,
allow 10-50
, then the DENY would have to either be entirely consumed by that range, ie, 34-38. OR, entirely consume the previous rule.9-51
. This is because the ranges actually represent lft and rgt values in a nested set model and you cannot have overlaps like I presented.
I didn't think to mention that when asking the question, but after seeing the working sample code below, I can see that this note is actually important.
(Edited example mysql to include OR instead of AND as per comment below)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
老实说,为什么要麻烦呢?只要您要查询的键已建立索引,只需将多个查询放在那里即可:
您可以通过构建解析器来稍微提高效率,但我会质疑这是否值得。所有 WHERE 子句项都将脱离索引,因此您不会阻止任何硬操作的发生(这意味着您不会通过执行此操作来停止全表扫描)。
因此,与其花时间构建一个系统来为您做这件事,不如实施一个简单的解决方案(将“允许”
OR
组合在一起,并将“Denys”AND
组合在一起)并继续前进去更重要的事情。然后,如果以后出现问题,请重新审视它。但我真的不认为这会成为一个太大的问题...编辑 好的,这是一个非常简单的算法来做到这一点。它使用字符串作为数据存储,因此对于较小的数字(低于 100 万)来说相当有效:
用法:
生成:
Honestly, why bother? As long as the key you're querying against is indexed, just put the multiple queries in there:
You could squeze a slight bit of efficiency by building a dissector, but I would question if it's worth it. All the WHERE clause items would be off of an index, so you're not preventing any hard operation from occurring (meaning you're not stopping a full-table-scan by doing it).
So rather than spending time building a system to do it for you, just implement an easy solution (
OR
ing together the Allows, andAND
ing together the Denys) and move on to more important things. Then if it becomes a problem later, revisit it then. But I really don't think this will ever become too big of a problem...Edit Ok, here's a very simple algorithm for doing this. It uses strings as the data store, so it's reasonably efficient for smaller numbers (below 1 million):
Usage:
Generates:
我花了一点时间试图解决这个问题(这是一个很好的问题),然后想出了这个。它不是最佳的,我也不保证它是完美的,但它可能会让您开始:
最后一个
var_dump
输出:编辑为使用第一个示例而不是第二个示例。
I spent a little time trying to solve this (it's a neat problem), and came up with this. It's not optimal, nor am I guaranteeing it's perfect, but it might get you started:
The last
var_dump
outputs:Edited to use the first example instead of the second.
我会一次处理一个指令,创建一个应包含的数字列表。然后最后将该列表转换为 where 子句的一组范围。这是一些伪代码:
I would process the instructions one at a time creating a list of numbers that should be included. Then finally translating that list into a set of ranges for the where clause. Here is some pseudo code:
我在 IRC 上询问并收到了两个回复。我将把它们都发布出来,以便其他人可能受益(这样我就不会失去它们,因为我很快就会详细了解它们)。
示例 1 TML
示例 2 (matslin)
I asked on IRC and received two responses. I'm going to post them both so that other people might benefit (and so that I don't lose them since I will take a look in detail at them both shortly).
Example 1 TML
Example 2 (matslin)