多对多关系过滤器
Posted
技术标签:
【中文标题】多对多关系过滤器【英文标题】:Many-to-many relation filter 【发布时间】:2012-11-06 14:45:36 【问题描述】:我需要使用与另一个表有 many2many 关系的类别表过滤我的查询。是否可以使用 many2many 关系过滤查询?
表res_partner
有many2many 字段category_id
与表res_partner_category.res_partner
相关,或者说合作伙伴可以有很多类别。我需要的是过滤res_partners
表,它的类别名为“商业”或“零售”。如果它没有任何这些类别,则不应显示。
res_partner
中还有另一个字段是category_value_ids
,并且与res_partners_category_value
有one2many
关系:
res_partner
具有以下具有关系的字段:
category_id
到 res_partner_category
(many2many)
category_value_ids
到 res_partner_category_value
(one2many)
name
(字符)
res_partner_category
具有以下具有关系的字段:
partner_ids
到 res_partner
(many2many)
name
(字符)
res_partner_category_value
具有以下具有关系的字段:
category_group_id
到 res_partner_category
(many2one)
category_id
到 res_partner_category
(many2one)
object_id
tores_partner
(many2one)
但如果我尝试在 SQL 查询中使用 res_partner_category_value
表,我会收到错误,我无法在查询中使用它。
例如,如果有 4 个合作伙伴属于这些类别:
首先:categ1、categ2、business 第二:零售 第三类:零售、商业 第四:categ1,categ2查询应返回第一、第二和第三伙伴。 一个人告诉我,不可能像这样使用 many2many 关系进行过滤。所以我想知道这真的不可能还是很复杂?
编辑:
我又找到了一张名为res_partner_category_rel
的表。我没有看到它,因为在 Openerp 管理界面中,您可以看到数据库的所有对象,但没有显示该表。您只能通过数据库直接看到它。
所以我被这个“失踪”的表弄糊涂了:
res_partner_category_rel:
partner_id
(many2one)
category_id
(many2one)
【问题讨论】:
我对每个表中的字段感到困惑。对于表 A 和 B 之间的多对多关系,A 和 B 都不应该有指向另一个表中记录的外键字段。相反,应该有一个单独的表 C,其中包含外键字段对(1 表示 A,1 表示 B)。但是根据您的描述,res_partner
包含一个 category_id
字段...为什么?
@j_random_hacker 这是 OpenERp 的一个特性:你可以定义一个从 A 到 B 的 many2many“字段”,关系表 C 由 ORM 自动(自动?)管理。
谢谢@DReispt,现在说得通了。顺便说一句,如果您在评论中的“@”之后放置一个空格,它似乎不会自动通知该人。
【参考方案1】:
这是你应该提供的测试用例:
CREATE TABLE partner (
partner_id serial PRIMARY KEY
, partner text
);
INSERT INTO partner (partner) VALUES
('partner1')
, ('partner2')
, ('partner3')
, ('partner4')
;
CREATE TABLE category (
category_id serial PRIMARY KEY
, category text
);
INSERT INTO category (category) VALUES
('categ1')
,('categ2')
,('business')
,('retail');
CREATE TABLE partner_category (
partner_id int REFERENCES partner(partner_id)
, category_id int REFERENCES category(category_id)
, CONSTRAINT cat_pk PRIMARY KEY (partner_id, category_id)
);
INSERT INTO partner_category (partner_id, category_id) VALUES
(1,1), (1,2), (1,3)
,(2,4)
,(3,3), (3,4)
,(4,1), (4,2);
这是您所追求的查询(许多个可能的变体之一):
SELECT p.*
FROM partner p
WHERE EXISTS (SELECT * FROM partner_category pc
WHERE pc.partner_id = p.partner_id AND pc.category_id = 3)
OR EXISTS (SELECT * FROM partner_category pc
WHERE pc.partner_id = p.partner_id AND pc.category_id = 4)
ORDER BY p.partner_id;
SQL Fiddle.
这里的关键词是关系划分。我们已经收集了一整套查询来处理这个相关问题下的这类问题:
How to filter SQL results in a has-many-through relation【讨论】:
其实没有 category 和 partner_category 这样的表没有字段partner_id
。你的查询看起来不错,但太糟糕了我不能使用它,因为表关系在 openerp 中有点不同......它有我写的关系。
@oerp:如果您的表格在结构上有所不同,那么我建议您使用我演示的设置来更新问题。因此,试图帮助的人有一些工作要做。然而,事实上,只要我们处理的是 m:n 关系,我的例子就应该成立。
同样在'and category_id=3',不应该是'and pc.category_id=3'吗?
感谢您的回答,我现在真的解决了,当我发现一张桌子没有出现时:)
@oerp:嗯,是的,category_id = 3
,应该是pc.category_id = 3
。无论哪种方式,它都可以工作 - 没有表限定,范围默认为pc
在子查询中。但是为了可读性我修改了它。很酷,它现在对你有用。 :)【参考方案2】:
正如您已经注意到的,many2one category_id
在数据库中并没有表示为表字段,而是表示为与合作伙伴和类别相关的表。
您需要的 SQL 可能如下所示:
SELECT p.*
FROM res_partner p
INNER JOIN res_partner_category_rel rel ON p.id = rel.partner_id
INNER JOIN res_partner_category c ON rel.category_id = c.id
WHERE c.id in (3,4)
如果你想在 python 对象中进行过滤,通常的search
call 应该可以工作:
list_ids = partner_model.search(cr, uid, [('category_id', 'in', [3,4])])
作为奖励,由于类别是按树组织的,您可以使用以下方法获取这些类别及其所有子类别:
list_ids = partner_model.search(cr, uid, [('category_id', 'child of', [3,4])])
【讨论】:
如您在上面看到的答案,解决了我的问题。但无论如何,谢谢,以后可能会派上用场。以上是关于多对多关系过滤器的主要内容,如果未能解决你的问题,请参考以下文章