查找记录的字段' name'不包含在任何其他记录中

时间:2014-05-31 02:13:57

标签: ruby-on-rails ruby-on-rails-3 postgresql activerecord

我的模型Foo包含String barString name。某些记录“bar包含其中name个其他记录。这是故意的。

我想找到“根Foo”记录 - 即name未出现在任何其他bar记录的Foo记录中的记录。

示例:

Foo
id: 1
name: 'foo1'
bar:  'something something'

id: 2
name: 'foo2'
bar:  'foo1 something'

id: 3
name: 'foo3'
bar:  'foo1, foo4'

我的方法root_foos将返回foo2foo3,因为它们的名称不会出现在任何bar字符串中。

编辑:我不想在这里使用关系或外键 - 只是这种方法。

2 个答案:

答案 0 :(得分:2)

SELECT f.*
FROM   foo f
WHERE  NOT EXISTS (
   SELECT 1
   FROM   foo f2
   WHERE  f.name <@ string_to_array(f2.bar, ', ')
   );

', '替换为您实际使用的分隔符 使用索引,这将更快。您可以构建一个功能性GIN索引来处理当前不幸的设计:

CREATE INDEX foo_bar_arr_gin_idx ON foo USING GIN (string_to_array(bar, ', '));

bar应该实现为数组而不是字符串。然后你可以简化查询和索引:
Table indexes for Text[] array columns
Why isn't my PostgreSQL array index getting used (Rails 4)?

规范化架构

如链接答案中所述,如果正确实现n:m关系,数据库模式将更清晰(查询和索引更简单,更快)。性能取决于许多变量。

CREATE TABLE foo
   foo_id serial PRIMARY KEY
 , foo    text
);

CREATE TABLE foo_foo
   foo_id1 int REFERENCES foo
 , foo_id2 int REFERENCES foo
 , PRIMARY KEY (foo_id1, foo_id2) -- provides necessary index automatically
);

然后您的数据将如下所示:

foo
foo_id: 1
foo: 'foo1'

foo_id: 2
foo: 'foo2'

foo_id: 3
foo:   'foo3'


foo_foo
foo_id1: 1
foo_id2: some_id

foo_id1: 1
foo_id2: some_other_id

foo_id1: 2
foo_id2: 1

foo_id1: 2
foo_id2: some_id

foo_id1: 3
foo_id2: 1

foo_id1: 3
foo_id2: 4

查询:

SELECT f.*
FROM   foo f
WHERE  NOT EXISTS (
   SELECT 1
   FROM   foo_foo f2
   WHERE  f2.foo_id2 = f.foo_id
   );

答案 1 :(得分:-1)

对于任意数量的记录,这将是非常缓慢的,如果这是您需要的任何频率的查询,我强烈建议重构您的架构,但是:

objs = Model.all.to_a
objs.select { |obj| !objs.any? { |inner_obj| inner_obj[:bar].index(obj[:name]) } }