sql - una - relacion uno a varios ejemplos
Filtro de relaciĆ³n de muchos a muchos (2)
Necesito filtrar mi consulta con la tabla de categorías que tiene una relación muy variada con otra tabla. ¿Es posible filtrar consultas con muchas relaciones de muchos?
La tabla res_partner
tiene many2many field category_id
relacionado con la tabla res_partner_category.res_partner
, o digamos que los partners pueden tener muchas categorías. Lo que necesito es filtrar la tabla res_partners
donde tiene la categoría llamada ''business'' o ''retail''. Si no tiene ninguna de estas categorías, no debería mostrarse.
También hay otro campo en res_partner
que es category_value_ids
y tiene one2many
relación res_partners_category_value
con res_partners_category_value
:
res_partner
tiene los siguientes campos con relaciones:
-
category_id
ares_partner_category
(many2many) -
category_value_ids
tores_partner_category_value
(one2many) -
name
(char)
res_partner_category
tiene los siguientes campos con relaciones:
-
partner_ids
ares_partner
(many2many) -
name
(char)
res_partner_category_value
tiene los siguientes campos con relaciones:
-
category_group_id
tores_partner_category
(many2one) -
category_id
tores_partner_category
(many2one) -
object_id
tores_partner
(many2one)
Pero si trato de usar la tabla res_partner_category_value
en la consulta SQL me sale un error que no puedo usar en la consulta.
Entonces, por ejemplo, si hay 4 socios con estas categorías:
- primero: categ1, categ2, negocio
- segundo: venta al por menor
- tercero: comercio minorista, negocios
- cuarto: categ1, categ2
La consulta debe devolver primero, segundo y tercer socio.
Una persona me dijo que no es posible filtrar así con muchas relaciones. Entonces me pregunto si realmente no es posible o simplemente es complicado.
EDITAR:
Encontré una tabla más llamada res_partner_category_rel
. No lo vi, porque en la interfaz de administración de Openerp, donde puedes ver todos los objetos de la base de datos, esa tabla no se muestra. Solo puede verlo directamente a través de la base de datos. Así que estaba confundido por esta tabla "perdida":
res_partner_category_rel:
-
partner_id
(many2one) -
category_id
(many2one)
Como ya ha notado, el many2one category_id
no está representado en la base de datos como un campo de tabla, sino como una tabla que relaciona Socios y Categorías.
El SQL que necesita podría verse así:
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)
Si desea hacer el filtro en el objeto python, la llamada de search
habitual debería funcionar:
list_ids = partner_model.search(cr, uid, [(''category_id'', ''in'', [3,4])])
Como beneficio adicional, dado que las Categorías están organizadas en un árbol, puede obtener esas categorías y todos sus hijos usando:
list_ids = partner_model.search(cr, uid, [(''category_id'', ''child of'', [3,4])])
Este es el caso de prueba que debería haber proporcionado:
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);
Y esta es la consulta que está buscando (una de las muchas variantes posibles):
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;
La palabra clave aquí es división relacional . Hemos reunido todo un arsenal de consultas para tratar esta clase de problemas bajo esta pregunta relacionada: