0
I am developing a system for storing documents for everyday use with PHP and mysql and for easy queries I added tags to these documentations and to ensure the integrity of the data I added another table called documentacao_tag. But I’m having trouble doing a query ,where the documentation contains exactly all related tags. Ex: check all documentation that has exactly the linux tag AND server tag.
I am looking for a solution to guarantee the integrity of the data, being able to change the modeling of the tables
Modeling of the database: SQL file for testing:
CREATE DATABASE teste;
USE teste;
CREATE TABLE IF NOT EXISTS `documentacao` (
`doc_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`doc_titulo` varchar(100) NOT NULL,
`doc_texto` text NOT NULL,
PRIMARY KEY (`doc_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=53 ;
INSERT INTO `documentacao` (`doc_id`, `doc_titulo`, `doc_texto`) VALUES
(1, 'Título 1', 'texto da notícia 1'),
(2, 'Título 2', 'texto da notícia 2 '),
(3, 'Título 3', 'texto da notícia 3');
CREATE TABLE IF NOT EXISTS `documentacao_tag` (
`doc_id` int(11) unsigned NOT NULL,
`tag_id` tinyint(4) unsigned NOT NULL,
PRIMARY KEY (`doc_id`,`tag_id`),
KEY `FK_documentacao_tag_tag` (`tag_id`),
KEY `doc_id` (`doc_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `documentacao_tag` (`doc_id`, `tag_id`) VALUES
(1, 1),
(3, 1),
(1, 2),
(2, 2),
(3, 2),
(3, 3);
CREATE TABLE IF NOT EXISTS `tag` (
`tag_id` tinyint(4) unsigned NOT NULL AUTO_INCREMENT,
`tag_desc` varchar(30) NOT NULL,
PRIMARY KEY (`tag_id`),
UNIQUE KEY `tag_desc` (`tag_desc`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=90 ;
INSERT INTO `tag` (`tag_id`, `tag_desc`) VALUES
(1, 'linux'),
(3, 'manual'),
(2, 'servidor');
ALTER TABLE `documentacao_tag`
ADD CONSTRAINT `FK_documentacao_tag_documentacao` FOREIGN KEY (`doc_id`) REFERENCES `documentacao` (`doc_id`),
ADD CONSTRAINT `FK_documentacao_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`tag_id`);
Output example by selecting documentation with linux tags (tag_id = 1) and server (tag_id = 3):
+----+--------------------+---------------------+
| 1 | Título da notícia 1 | texto da notícia 1 |
+----+--------------------+---------------------+
| 3 | Título da notícia 3 | texto da notícia 3 |
+----+--------------------+---------------------+
I got a solution, but I do not believe it is the most ideal, and it depends on the interaction with PHP to concatenate SQL
Example by selecting tag_id 1 and 2:
SELECT
documentacao.doc_id,
documentacao.doc_titulo,
documentacao.doc_texto
FROM
documentacao,
documentacao_tag,
tag
WHERE documentacao.doc_id = documentacao_tag.doc_id
AND documentacao_tag.tag_id = tag.tag_id
AND documentacao_tag.tag_id IN (1)
AND documentacao_tag.doc_id IN (
SELECT
documentacao.doc_id
FROM
documentacao,
documentacao_tag,
tag
WHERE documentacao.doc_id = documentacao_tag.doc_id
AND documentacao_tag.tag_id = tag.tag_id
AND documentacao_tag.tag_id IN (2)
ORDER BY documentacao.doc_id
)
ORDER BY documentacao.doc_id
Note: I have to concatenate dynamically with PHP the line below for each tag added to the filter
AND documentacao_tag.doc_id IN (
SELECT
documentacao.doc_id
FROM
documentacao,
documentacao_tag,
tag
WHERE documentacao.doc_id = documentacao_tag.doc_id
AND documentacao_tag.tag_id = tag.tag_id
AND documentacao_tag.tag_id IN (id_da_tag_a_ser_filtrada)
ORDER BY documentacao.doc_id
)
I guess I couldn’t figure out what you want to do, but a
inner join
would be enough, no?– Jéf Bueno
@jbueno 13 Well, at least I didn’t get any solution that returns the desired answer, with the exception of the one I posted at the end of the question, but it needs the interaction of a programming language. If you know a solution could post just below?
– adrianosymphony
@adrianosymphony was able to test the solution I posted?
– KaduAmaral
Did @Kaduamaral’s answer solve your problem? If not, I’ll think of a way to do it
– Jéf Bueno
I think the title of the question could be improved. If someone knows a better way to express doubt feel free to edit it.
– adrianosymphony