Mysql: cómo seleccionar grupos que tienen ciertos valores?
Pregunta
dicen que no es tal tabla:
mysql> SELECT * FROM tags;
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1 | 2 |
| 1 | 3 |
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
+---------+--------+
5 rows in set (0.00 sec)
nombres campo son bastante auto-explicativo. Quiero seleccionar post_id
s que tienen de 1 y 3 tag_id
s, por lo que en este ejemplo es sólo 1
. Pensé en algo así como
Después de haber SELECT post_id FROM tags GROUP BY post_id HAVING ...
me gustaría tag_id
s lista que están presentes en este grupo. ¿Cómo lo hago?
Solución
Si no hay restricciones únicas tratan:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(DISTINCT tag_id) = 2;
O utilice esta cláusula HAVING
, si tratara de detectar sólo dos valores tag_id
:
HAVING MIN(tag_id) <> MAX(tag_id)
Si post_id y tag_id ambos tienen una restricción única, esto debería funcionar también:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(*) = 2;
Otros consejos
Se podría probar un auto join (N tag_id -> N se unen a) pero probablemente no es rápido
SELECT t1.post_id
FROM tags t1 INNER JOIN tags t2 ON t1.post_id = t2.post_id
WHERE t1.tag_id = 1 AND t2.tag_id = 3
He hecho algunas suposiciones acerca de sus otras tablas. (Es decir, que tiene una tabla de mensajes que he llamado posts
y uno con tag_id como el PK que he llamado tag_table
para evitar una nameclash con la tabla de mensajes / tags que puedo ver que ya tags
llamada)
¿Quieres mensajes donde no existe una etiqueta de la lista {1,3} para el que no existe un registro coincidente con el correspondiente post_id / tag_id esta manera puede utilizar un doble NO EXISTE constructo de la siguiente manera.
SELECT post_id
FROM posts p
WHERE NOT EXISTS
(SELECT * FROM tag_table tt
WHERE tag_id IN (1,3)
AND NOT EXISTS
(SELECT * FROM tags t
WHERE t.tag_id = tt.tag_id and
p.post_id = t.post_id)
)
Otro enfoque alternativo es utilizar GROUP BY y Count. A revisión de los enfoques a este problema es aquí .
SELECT post_id
FROM ( SELECT post_id,
count(tag_id) AS counter
FROM tags
WHERE tag_id IN (1,3)
GROUP BY post_id
)
WHERE counter = 2
Uso GROUP_CONCAT () para la segunda parte de su pregunta ??p>
SELECT post_id,
GROUP_CONCAT(tag_id ORDER BY tag_id ASC SEPARATOR ',')
FROM tags
¿Qué tal
SELECT *
FROM tags
WHERE post_id in
(SELECT post_id AS pid
FROM tags
WHERE 1 IN (SELECT tag_id FROM tags WHERE post_id = pid)
AND 3 IN (SELECT tag_id FROM tags WHERE post_id = pid)
);
DONDE versión de la solución de Guardián @
SELECT DISTINCT t1.post_id
FROM tags t1, tags t2
WHERE
t1.post_id = t2.post_id AND
t1.tag_id = 1 AND t2.tag_id = 3