我有一个 mnesia 表,其中包含 f1、f2、f3 字段。现在,如果我要选择字段值为 V1 的所有行,我将使用mnesia:select
并匹配规范或简单的mnesia:match_object
. 现在我需要选择所有具有 V1、V2、V3 ... 或 Vn(任意长度的列表)的行作为字段 f1 的值。在 SQL 中,我会做类似的事情
SELECT * FROM tablename WHERE f3 IN (V1, V2, V3, ... , Vn)
我如何在记忆中做到这一点?
对于这个问题的匹配规范解决方案,如果 QLC 被测量为不够有效。
> ets:fun2ms(fun ({_,X}=E) when X == a -> E end).
[{{'_','$1'},[{'==','$1',a}],['$_']}]
ets:fun2ms 是一个解析转换,可以将一些乐趣转换为匹配规范值。我用它作为获得我想要的 matchspec 的快速方法。我们得到一个带有 matchspec 的列表,它找到第二个元素是 a 的元组。我们可以对其他键重复它。
因此,让我们用一些东西来填充一个 ets 表来尝试一下,然后创建一个 matchspec,它只匹配第二个元素为“a”或“c”的项目。(我输入这个
ets:new(foo, [named_table]).
ets:insert(foo, [{1,a},{2,b},{3,c},{4,d}]).
Vs = [a,c].
MS = [{{'_','$1'},[{'==','$1',V}],['$_']} || V <- Vs].
ets:select(foo, MS).
当我运行它时,我得到:
[{1,a},{3,c}]
克里斯蒂安指出了很好的解决方案,但它可以变得更简单一些
2> ets:fun2ms(fun ({_,a}=E) -> E end).
[{{'_',a},[],['$_']}]
所以对于你匹配你可以制作更简单的匹配规范
4> ets:new(foo, [named_table]).
foo
5> ets:insert(foo, [{1,a},{2,b},{3,c},{4,d}]).
true
6> Vs = [a,c].
[a,c]
7> MS = [{{'_',V},[],['$_']} || V <- Vs].
[{{'_',a},[],['$_']},{{'_',c},[],['$_']}]
8> ets:select(foo, MS).
[{1,a},{3,c}]
如果您需要“复杂”查询,那么 QLC 是一种简洁的表述方式。QLC 是一种解析转换,它允许您在各种表(包括 mnesia 表)上使用列表理解语法。
您必须具有以下包含,因为它启用了使 QLC 在此源文件中成为可能的解析转换。
-include_lib("stdlib/include/qlc.hrl").
基本查询表单如下所示,创建查询句柄,然后评估查询。
QH = qlc:q([X || X <- Xs]),
qlc:eval(QH).
然后,您可以使用http://www.erlang.org/doc/man/mnesia.html#table-1在 mnesia 表中获取后端的 QLC 表。因此,您的查询可以实现如下:
Vs = [V1,V2,...Vn],
QH = qlc:q([X || X <- mnesia:table(tablename),
lists:member(X#tablename.f3, Vs)]),
qlc:eval(QH).
这需要进行表扫描,但效率不高。如果您在 f3 列上有一个索引,那么您可以转而先查询 f3 = V1,然后是 V2 等的条目,然后合并结果。
附言
另一种方法是从 V 值列表中创建一个非常复杂的匹配规范并运行 mnesia:select。