SQLITE: un problema de etiquetas y productos


10

Estoy buscando una forma de crear una consulta para hacer lo siguiente:

Consideremos 3 tablas:

  • productos: Lista de productos
  • etiquetas: lista de etiquetas
  • tag_ties: tabla utilizada para asociar una etiqueta a un producto

Consideremos esta estructura para cada tabla:

Productos:

  • id (int, autoincrement)
  • nombre (varchar, nombre del producto)

Etiquetas:

  • id (int autoincrement)
  • etiqueta (varchar, etiqueta de la etiqueta)

Tag_ties:

  • id (int, autoincrement)
  • tag_id (int, referencia a un identificador de etiqueta)
  • ref_id (int, referencia a una identificación del producto)

Lo que quiero:

Obtenga todos los productos etiquetados con etiquetas ID 10, 11 y 12, por ejemplo.

Esta consulta no funciona, ya que devuelve los productos que tienen al menos una de las etiquetas:

select 
    p.name as name,
    p.id as id
from 
    products p inner join tag_ties ties
on
    p.id=ties.ref_id
where
    ties.ref_id=p.id and
    ties.tag_id in (10,11,12)
group by 
    p.id
order by 
    p.name asc

Respuestas:


9

Intenta algo como esto:

select
    t1.id,
    t1.name
from
    (
    select
        p.name as name,
        p.id as id
    from
        products p inner join tag_ties ties
    on
        p.id=ties.ref_id
    where
        ties.tag_id in (10,11,12)
    ) as t1
group by
    t1.id,
    t1.name
having
    count(t1.id) = 3
order by
    t1.name asc
;

Está funcionando :)
Julien L

11

Puede resolver este problema utilizando declaraciones de intersección. Haga una selección por separado para cada tag_id y únalas con intersecciones y solo obtendrá los registros que coincidan con los tres tag_ids.

select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id
where tag_ties.tag_id = 10
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 11
intersect
select products.id, products.name from 
products join tag_ties
on tag_ties.ref_id = products.id 
where tag_ties.tag_id = 12

Aquí hay un artículo de referencia sobre el uso de intersect

También puede usar una vista temporal para que se vea un poco mejor.

create temporary view temp_view as 
select name, products.id as id, tag_ties.tag_id as tag_id 
from products join tag_ties
on tag_ties.ref_id = products.id

select name, id from temp_view where tag_id = 10
intersect ...

8

La subconsulta de la respuesta seleccionada no es necesaria. Para seleccionar productos con todos los identificadores de etiqueta dados, la consulta puede ser simplemente:

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id IN (10, 11, 12)
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

Extendiendo esta idea, también podemos consultar en función de las etiquetas de etiqueta en una sola toma. Para seleccionar productos con las etiquetas ('foo', 'bar', 'baz'):

SELECT 
    p.*
FROM 
    products AS p
INNER JOIN
    tags AS t
ON
    t.label IN ('foo', 'bar', 'baz')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id
HAVING 
    COUNT(p.id)=3

Para complicarlo un poco, podemos usar una subconsulta para mezclar intersection ( AND) y union ( OR). La siguiente consulta devolverá productos con todas las etiquetas del grupo ('foo', 'bar')y al menos una de las etiquetas del grupo ('baz', 'ding'):

SELECT 
    p.*
FROM 
    (
    SELECT 
        p.*
    FROM 
        products AS p
    INNER JOIN 
        tags AS t
    ON
        t.label IN ('foo', 'bar')
    INNER JOIN 
        tag_ties AS tt
    ON
        tt.ref_id = p.id
    AND 
        tt.tag_id = t.id
    GROUP BY 
        p.id
    HAVING 
        COUNT(p.id)=2
    ) AS p
INNER JOIN 
    tags AS t
ON 
    t.label IN ('baz', 'ding')
INNER JOIN
    tag_ties AS tt
ON
    tt.ref_id = p.id
AND 
    tt.tag_id = t.id
GROUP BY 
    p.id

2
¿No necesitas un JOIN? No, técnicamente no, pero ¿hay alguna razón para no usarlo? ¿Y volviendo a la notación SQL-89 de uniones implícitas?
ypercubeᵀᴹ

55
Estoy votando porque deberías usar JOIN siempre. stackoverflow.com/questions/5654278/... Sin un JOIN explícito, su código no se implementaría en mi tienda
gbn

3
Hola chicos, gracias por decirme que las uniones implícitas son de mal estilo. Principalmente pretendía señalar que la subconsulta de la respuesta seleccionada no era necesaria. Edité la respuesta para usar combinaciones. Si ve algo más en mis consultas, hágamelo saber.
moraes

55
+1 por tomar el voto negativo sin enojarse y tener en cuenta los consejos para mejorar sus habilidades.
Zane

2
Lo que dijo @Zane. +1 también
gbn
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.